@react-hive/honey-utils 3.24.0 → 3.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","mappings":"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","sources":["webpack://@react-hive/honey-utils/./src/dom/dom.ts","webpack://@react-hive/honey-utils/./src/a11y/focus/is-html-element-focusable.ts","webpack://@react-hive/honey-utils/./src/a11y/focus/get-focusable-html-elements.ts","webpack://@react-hive/honey-utils/./src/a11y/focus/move-focus-within-container.ts","webpack://@react-hive/honey-utils/./src/guards.ts","webpack://@react-hive/honey-utils/./src/array.ts","webpack://@react-hive/honey-utils/./src/function/function.ts","webpack://@react-hive/honey-utils/./src/async/async.ts","webpack://@react-hive/honey-utils/./src/async/delay.ts","webpack://@react-hive/honey-utils/./src/async/timeout.ts","webpack://@react-hive/honey-utils/./src/async/retry.ts","webpack://@react-hive/honey-utils/./src/string/is-string.ts","webpack://@react-hive/honey-utils/./src/dom/file/download-file.ts","webpack://@react-hive/honey-utils/./src/dom/layout/overflow.ts","webpack://@react-hive/honey-utils/./src/geometry/layout/calculate-center-offset.ts","webpack://@react-hive/honey-utils/./src/dom/layout/center-element-in-container.ts","webpack://@react-hive/honey-utils/./src/dom/transform/parse-2d-matrix.ts","webpack://@react-hive/honey-utils/./src/env/storage/local-storage.ts","webpack://@react-hive/honey-utils/./src/file.ts","webpack://@react-hive/honey-utils/./src/function/invoke-if-function.ts","webpack://@react-hive/honey-utils/./src/geometry/resolve-bounded-delta.ts","webpack://@react-hive/honey-utils/./src/geometry/apply-inertia-step.ts","webpack://@react-hive/honey-utils/./src/id/generate-ephemeral-id.ts","webpack://@react-hive/honey-utils/./src/intersection/get-dom-rect-intersection-ratio.ts","webpack://@react-hive/honey-utils/./src/intersection/resolve-axis-delta.ts","webpack://@react-hive/honey-utils/./src/math/math.ts","webpack://@react-hive/honey-utils/./src/math/hash-string.ts","webpack://@react-hive/honey-utils/./src/object.ts","webpack://@react-hive/honey-utils/./src/string/to-kebab-case.ts","webpack://@react-hive/honey-utils/./src/string/camel-to-dash-case.ts","webpack://@react-hive/honey-utils/./src/string/camel-to-words.ts","webpack://@react-hive/honey-utils/./src/string/split-string-into-words.ts","webpack://@react-hive/honey-utils/./src/string/is-nil-or-empty-string.ts","webpack://@react-hive/honey-utils/./src/string/parse-file-name.ts","webpack://@react-hive/honey-utils/./src/string/find-char-indices.ts","webpack://@react-hive/honey-utils/./src/string/for-each-char.ts","webpack://@react-hive/honey-utils/./src/string/get-words-initials.ts","webpack://@react-hive/honey-utils/./src/string/split-map-join.ts","webpack://@react-hive/honey-utils/./src/tree/flatten-tree.ts","webpack://@react-hive/honey-utils/./src/tree/get-tree-children.ts","webpack://@react-hive/honey-utils/./src/tree/search-tree.ts"],"sourcesContent":["/**\n * Creates a clone of a Blob object.\n *\n * @param blob - The Blob object to clone.\n *\n * @returns A new Blob with the same content and type as the original.\n */\nexport const cloneBlob = (blob: Blob): Blob => new Blob([blob], { type: blob.type });\n\n/**\n * Returns the bounding DOMRect of an element based on offset and client dimensions.\n *\n * This utility is useful when you need a stable, layout-based rect\n * without triggering a reflow via `getBoundingClientRect()`.\n *\n * @param element - The target HTML element.\n * @returns A `DOMRect` representing the element’s offset position and size.\n */\nexport const getElementOffsetRect = (element: HTMLElement): DOMRect =>\n new DOMRect(element.offsetLeft, element.offsetTop, element.clientWidth, element.clientHeight);\n\n/**\n * Determines whether the given HTMLElement is an HTMLAnchorElement.\n *\n * Acts as a type guard so that TypeScript narrows `element` to\n * `HTMLAnchorElement` when the function returns `true`.\n *\n * An element qualifies as an anchor by having a tag name of `\"A\"`.\n *\n * @param element - The element to test.\n *\n * @returns Whether the element is an anchor element.\n */\nexport const isAnchorHtmlElement = (element: HTMLElement): element is HTMLAnchorElement =>\n element.tagName === 'A';\n\n/**\n * Checks whether an element is explicitly marked as contenteditable.\n *\n * Browsers treat elements with `contenteditable=\"true\"` as focusable,\n * even if they are not normally keyboard-focusable.\n *\n * @param element - The element to inspect.\n *\n * @returns True if `contenteditable=\"true\"` is set.\n */\nexport const isContentEditableHtmlElement = (element: HTMLElement) =>\n element.getAttribute('contenteditable') === 'true';\n","import type { Nullable } from '~/types';\nimport { isAnchorHtmlElement, isContentEditableHtmlElement } from '~/dom';\n\nexport const FOCUSABLE_HTML_TAGS = ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON', 'A'];\n\n/**\n * Determines whether an HTMLElement is focusable under standard browser rules.\n *\n * The function checks a combination of factors:\n * - The element must be rendered (not `display: none` or `visibility: hidden`).\n * - Disabled form controls are never focusable.\n * - Elements with `tabindex=\"-1\"` are intentionally removed from the focus order.\n * - Certain native HTML elements are inherently focusable (e.g. inputs, buttons, anchors with `href`).\n * - Elements with `contenteditable=\"true\"` are treated as focusable.\n * - Any element with a valid `tabindex` (not null) is considered focusable.\n *\n * This logic approximates how browsers and the accessibility tree\n * determine real-world focusability—not just tabindex presence.\n *\n * @param element - The element to test. `null` or `undefined` will return `false`.\n *\n * @returns Whether the element is focusable.\n */\nexport const isHtmlElementFocusable = (element: Nullable<HTMLElement>): boolean => {\n if (!element) {\n return false;\n }\n\n const style = window.getComputedStyle(element);\n if (style.visibility === 'hidden' || style.display === 'none') {\n return false;\n }\n\n if ('disabled' in element && element.disabled) {\n return false;\n }\n\n // Explicitly removed from tab order\n const tabIndex = element.getAttribute('tabindex');\n if (tabIndex === '-1') {\n return false;\n }\n\n if (FOCUSABLE_HTML_TAGS.includes(element.tagName)) {\n if (isAnchorHtmlElement(element)) {\n return element.href !== '';\n }\n\n return true;\n }\n\n if (isContentEditableHtmlElement(element)) {\n return true;\n }\n\n return tabIndex !== null;\n};\n","import { isHtmlElementFocusable } from '~/a11y';\n\n/**\n * Collects all focusable descendant elements within a container.\n *\n * The function queries *all* elements under the container and filters them\n * using `isHtmlElementFocusable`, producing a reliable list of elements\n * that can receive keyboard focus in real-world browser conditions.\n *\n * @param container - The root container whose focusable children will be found.\n *\n * @returns An array of focusable HTMLElements in DOM order.\n */\nexport const getFocusableHtmlElements = (container: HTMLElement): HTMLElement[] =>\n Array.from(container.querySelectorAll<HTMLElement>('*')).filter(isHtmlElementFocusable);\n","import type { Nullable } from '~/types';\nimport { getFocusableHtmlElements } from '~/a11y';\n\nexport type FocusMoveDirection = 'next' | 'previous';\n\nexport interface MoveFocusWithinContainerOptions {\n /**\n * Whether focus navigation should wrap around when reaching\n * the beginning or end of the focusable elements list.\n *\n * When enabled, moving past the last element focuses the first,\n * and moving before the first focuses the last.\n *\n * @default true\n */\n wrap?: boolean;\n /**\n * Custom resolver for determining the next focus index.\n *\n * When provided, this function overrides the default navigation logic\n * and receives full control over how the focus moves.\n *\n * @param currentIndex - Index of the currently focused element.\n * @param direction - Direction in which focus is moving.\n * @param elements - Ordered list of focusable elements within the container.\n *\n * @returns The index of the element to focus next, or `null` to prevent focus movement.\n */\n getNextIndex?: (\n currentIndex: number,\n direction: FocusMoveDirection,\n elements: HTMLElement[],\n ) => Nullable<number>;\n}\n\n/**\n * Moves focus to the next or previous focusable element within a container.\n *\n * This utility is commonly used to implement accessible keyboard navigation patterns such as:\n * - roving tabindex\n * - custom dropdowns\n * - tablists\n * - menus\n * - horizontal or vertical navigation groups\n *\n * Focus movement is scoped to a container and operates on the list of\n * focusable descendants returned by `getFocusableHtmlElements`.\n *\n * @param direction - Direction in which focus should move (`'next'` or `'previous'`).\n * @param container - Optional container that defines the focus scope.\n * If omitted, the parent element of the currently focused element is used.\n * @param options - Optional configuration controlling wrapping behavior and custom index resolution.\n *\n * @remarks\n * - This function reads from and mutates the document's focus state.\n * - If no active element exists, no container can be resolved,\n * or the active element is not part of the focusable set, no action is taken.\n * - When `getNextIndex` is provided, it fully overrides the default wrapping and directional logic.\n */\nexport const moveFocusWithinContainer = (\n direction: FocusMoveDirection,\n container: Nullable<HTMLElement> = null,\n { wrap = true, getNextIndex }: MoveFocusWithinContainerOptions = {},\n): void => {\n const activeElement = document.activeElement as Nullable<HTMLElement>;\n const scope = container ?? activeElement?.parentElement;\n\n if (!activeElement || !scope) {\n return;\n }\n\n const focusableElements = getFocusableHtmlElements(scope);\n if (focusableElements.length === 0) {\n return;\n }\n\n const currentIndex = focusableElements.indexOf(activeElement);\n if (currentIndex === -1) {\n return;\n }\n\n let nextIndex: Nullable<number>;\n\n if (getNextIndex) {\n nextIndex = getNextIndex(currentIndex, direction, focusableElements);\n } else {\n if (direction === 'next') {\n nextIndex = currentIndex + 1;\n\n if (nextIndex >= focusableElements.length) {\n nextIndex = wrap ? 0 : null;\n }\n } else {\n nextIndex = currentIndex - 1;\n\n if (nextIndex < 0) {\n nextIndex = wrap ? focusableElements.length - 1 : null;\n }\n }\n }\n\n if (nextIndex === null) {\n return;\n }\n\n focusableElements[nextIndex]?.focus();\n};\n","export function assert(condition: any, message: string): asserts condition {\n if (!condition) {\n throw new Error(message);\n }\n}\n\n/**\n * Checks if a value is null.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is null; otherwise, `false`.\n */\nexport const isNull = (value: unknown): value is null => value === null;\n\n/**\n * Checks if a value is null or undefined.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is `null` or `undefined`, otherwise `false`.\n */\nexport const isNil = (value: unknown): value is null | undefined =>\n value === undefined || value === null;\n\n/**\n * Checks if a value is neither `null` nor `undefined`.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is defined (not `null` or `undefined`); otherwise, `false`.\n */\nexport const isDefined = <T>(value: T): value is NonNullable<T> =>\n value !== null && value !== undefined;\n\n/**\n * Checks if a value is undefined.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is undefined; otherwise, `false`.\n */\nexport const isUndefined = (value: unknown): value is undefined => value === undefined;\n\n/**\n * Checks if a value is a number.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a number; otherwise, `false`.\n */\nexport const isNumber = (value: unknown): value is number => typeof value === 'number';\n\n/**\n * Checks if a value is a boolean.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a boolean; otherwise, `false`.\n */\nexport const isBool = (value: unknown): value is boolean => typeof value === 'boolean';\n\n/**\n * Checks if a value is an object.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an object; otherwise, `false`.\n */\nexport const isObject = (value: unknown): value is object => typeof value === 'object';\n\n/**\n * Checks if a value is an empty object (no own enumerable properties).\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an empty object; otherwise, `false`.\n */\nexport const isEmptyObject = (value: unknown): value is Record<string, never> =>\n isObject(value) && !isNull(value) && Object.keys(value).length === 0;\n\n/**\n * Checks if a value is a Date object.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Date object; otherwise, `false`.\n */\nexport const isDate = (value: unknown): value is Date => value instanceof Date;\n\n/**\n * Checks if a value is a `Blob`.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Blob object; otherwise, `false`.\n */\nexport const isBlob = (value: unknown): value is Blob => value instanceof Blob;\n\n/**\n * Checks if a value is an `Error` object.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an Error instance; otherwise, `false`.\n */\nexport const isError = (value: unknown): value is Error => value instanceof Error;\n\n/**\n * Checks if a value is a valid Date object (not Invalid Date).\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a valid Date object; otherwise, `false`.\n */\nexport const isValidDate = (value: unknown): value is Date =>\n isDate(value) && !isNaN(value.getTime());\n\n/**\n * Checks if a value is a RegExp object.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a RegExp object; otherwise, `false`.\n */\nexport const isRegExp = (value: unknown): value is RegExp => value instanceof RegExp;\n\n/**\n * Checks if a value is a Map.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Map; otherwise, `false`.\n */\nexport const isMap = (value: unknown): value is Map<unknown, unknown> => value instanceof Map;\n\n/**\n * Checks if a value is a Set.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Set; otherwise, `false`.\n */\nexport const isSet = (value: unknown): value is Set<unknown> => value instanceof Set;\n\n/**\n * Checks if a value is a Symbol.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Symbol; otherwise, `false`.\n */\nexport const isSymbol = (value: unknown): value is symbol => typeof value === 'symbol';\n\n/**\n * Checks if a value is a finite number.\n *\n * A finite number is a number that is not `NaN`, `Infinity`, or `-Infinity`.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a finite number; otherwise, `false`.\n *\n * @example\n * ```ts\n * isFiniteNumber(10); // true\n * isFiniteNumber(3.14); // true\n * isFiniteNumber(-5); // true\n * ```\n *\n * @example\n * ```ts\n * isFiniteNumber(NaN); // false\n * isFiniteNumber(Infinity); // false\n * isFiniteNumber(-Infinity); // false\n * ```\n *\n * @example\n * ```ts\n * isFiniteNumber('10'); // false\n * isFiniteNumber(null); // false\n * isFiniteNumber(undefined); // false\n * ```\n */\nexport const isFiniteNumber = (value: unknown): value is number =>\n isNumber(value) && isFinite(value);\n\n/**\n * Checks if a value is an integer.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an integer; otherwise, `false`.\n */\nexport const isInteger = (value: unknown): value is number =>\n isNumber(value) && Number.isInteger(value);\n\n/**\n * Checks if a value is a decimal number (finite and non-integer).\n *\n * A decimal number is a finite number that has a fractional part (i.e. not an integer).\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a decimal number; otherwise, `false`.\n *\n * @example\n * ```ts\n * isDecimal(1.5); // true\n * isDecimal(-0.25); // true\n * isDecimal(0.1); // true\n * ```\n *\n * @example\n * ```ts\n * isDecimal(1); // false\n * isDecimal(0); // false\n * isDecimal(-10); // false\n * ```\n *\n * @example\n * ```ts\n * isDecimal(NaN); // false\n * isDecimal(Infinity); // false\n * ```\n *\n * @example\n * ```ts\n * isDecimal('1.5'); // false\n * isDecimal(null); // false\n * isDecimal(undefined); // false\n * ```\n */\nexport const isDecimal = (value: unknown): value is number =>\n isFiniteNumber(value) && !Number.isInteger(value);\n","import { assert } from '~/guards';\n\n/**\n * Checks if a value is an array.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an array; otherwise, `false`.\n */\nexport const isArray = (value: unknown): value is unknown[] => Array.isArray(value);\n\n/**\n * Checks if a value is an empty array.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an empty array; otherwise, `false`.\n */\nexport const isEmptyArray = (value: unknown): value is [] => isArray(value) && value.length === 0;\n\n/**\n * Represents all falsy values.\n */\ntype Falsy = false | null | undefined | 0 | '';\n\n/**\n * Removes all falsy values from an array.\n *\n * Falsy values include: `false`, `0`, `''` (empty string), `null`, `undefined`, and `NaN`.\n *\n * Useful for cleaning up arrays with optional, nullable, or conditionally included items.\n *\n * @template T - The type of the truthy items.\n *\n * @param array - An array possibly containing falsy values.\n *\n * @returns A new array containing only truthy values of type `T`.\n *\n * @example\n * ```ts\n * compact([0, 1, false, 2, '', 3, null, undefined, NaN]); // [1, 2, 3]\n * ```\n */\nexport const compact = <T>(array: (T | Falsy)[]): T[] => array.filter(Boolean) as T[];\n\n/**\n * Returns a new array with duplicate values removed.\n *\n * Uses Set for efficient duplicate removal while preserving the original order.\n *\n * @template T - The type of the items in the array.\n *\n * @param array - The input array that may contain duplicate values.\n *\n * @returns A new array with only unique values, maintaining the original order.\n *\n * @example\n * ```ts\n * unique([1, 2, 2, 3, 1, 4]); // [1, 2, 3, 4]\n * unique(['a', 'b', 'a', 'c']); // ['a', 'b', 'c']\n * ```\n */\nexport const unique = <T>(array: T[]): T[] => [...new Set(array)];\n\n/**\n * Splits an array into chunks of the specified size.\n *\n * Useful for pagination, batch processing, or creating grid layouts.\n *\n * @template T - The type of the items in the array.\n *\n * @param array - The input array to be chunked.\n * @param size - The size of each chunk. Must be greater than 0.\n *\n * @returns An array of chunks, where each chunk is an array of the specified size\n * (except possibly the last chunk, which may be smaller).\n *\n * @example\n * ```ts\n * chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]\n * chunk(['a', 'b', 'c', 'd'], 3); // [['a', 'b', 'c'], ['d']]\n * ```\n */\nexport const chunk = <T>(array: T[], size: number): T[][] => {\n assert(size > 0, 'Chunk size must be greater than 0');\n\n return Array.from({ length: Math.ceil(array.length / size) }, (_, index) =>\n array.slice(index * size, (index + 1) * size),\n );\n};\n\n/**\n * Returns an array containing elements that exist in all provided arrays.\n *\n * @template T - The type of the items in the arrays.\n *\n * @param arrays - Two or more arrays to find common elements from.\n *\n * @returns A new array containing only the elements that exist in all input arrays.\n *\n * @example\n * ```ts\n * intersection([1, 2, 3], [2, 3, 4]); // [2, 3]\n * intersection(['a', 'b', 'c'], ['b', 'c', 'd'], ['b', 'e']); // ['b']\n * ```\n */\nexport const intersection = <T>(...arrays: T[][]): T[] => {\n if (arrays.length === 0) {\n return [];\n }\n\n if (arrays.length === 1) {\n return [...arrays[0]];\n }\n\n const [first, ...rest] = arrays;\n const uniqueFirst = unique(first);\n\n return uniqueFirst.filter(item => rest.every(array => array.includes(item)));\n};\n\n/**\n * Returns elements from the first array that don't exist in the second array.\n *\n * @template T - The type of the items in the arrays.\n *\n * @param array - The source array.\n * @param exclude - The array containing elements to exclude.\n *\n * @returns A new array with elements from the first array that don't exist in the second array.\n *\n * @example\n * ```ts\n * difference([1, 2, 3, 4], [2, 4]); // [1, 3]\n * difference(['a', 'b', 'c'], ['b']); // ['a', 'c']\n * ```\n */\nexport const difference = <T>(array: T[], exclude: T[]): T[] =>\n array.filter(item => !exclude.includes(item));\n\ntype PipeFn = (arg: unknown) => unknown;\n\ntype Pipe = {\n <A, B>(fn1: (a: A) => B): (a: A) => B;\n <A, B, C>(fn1: (a: A) => B, fn2: (b: B) => C): (a: A) => C;\n <A, B, C, D>(fn1: (a: A) => B, fn2: (b: B) => C, fn3: (c: C) => D): (a: A) => D;\n <A, B, C, D, E>(\n fn1: (a: A) => B,\n fn2: (b: B) => C,\n fn3: (c: C) => D,\n fn4: (d: D) => E,\n ): (a: A) => E;\n <A, B, C, D, E, F>(\n fn1: (a: A) => B,\n fn2: (b: B) => C,\n fn3: (c: C) => D,\n fn4: (d: D) => E,\n fn5: (e: E) => F,\n ): (a: A) => F;\n (...fns: PipeFn[]): (arg: unknown) => unknown;\n};\n\n/**\n * Composes multiple unary functions into a single function, applying them from left to right.\n *\n * Useful for building a data processing pipeline where the output of one function becomes the input of the next.\n *\n * Types are inferred up to 5 chained functions for full type safety. Beyond that, it falls back to the unknown.\n *\n * @param fns - A list of unary functions to compose.\n *\n * @returns A new function that applies all functions from left to right.\n *\n * @example\n * ```ts\n * const add = (x: number) => x + 1;\n * const double = (x: number) => x * 2;\n * const toStr = (x: number) => `Result: ${x}`;\n *\n * const result = pipe(add, double, toStr)(2);\n * // => 'Result: 6'\n * ```\n */\nexport const pipe: Pipe =\n (...fns: PipeFn[]) =>\n (arg: unknown) =>\n fns.reduce((prev, fn) => fn(prev), arg);\n\ntype ComposeFn = (arg: unknown) => unknown;\n\ntype Compose = {\n <A, R>(fn1: (a: A) => R): (a: A) => R;\n <A, B, R>(fn1: (b: B) => R, fn2: (a: A) => B): (a: A) => R;\n <A, B, C, R>(fn1: (c: C) => R, fn2: (b: B) => C, fn3: (a: A) => B): (a: A) => R;\n <A, B, C, D, R>(\n fn1: (d: D) => R,\n fn2: (c: C) => D,\n fn3: (b: B) => C,\n fn4: (a: A) => B,\n ): (a: A) => R;\n <A, B, C, D, E, R>(\n fn1: (e: E) => R,\n fn2: (d: D) => E,\n fn3: (c: C) => D,\n fn4: (b: B) => C,\n fn5: (a: A) => B,\n ): (a: A) => R;\n (...fns: ComposeFn[]): (arg: unknown) => unknown;\n};\n\n/**\n * Composes multiple unary functions into a single function, applying them from **right to left**.\n *\n * Often used for building functional pipelines where the innermost function runs first.\n * Types are inferred up to 5 chained functions for full type safety.\n *\n * @param fns - A list of unary functions to compose.\n *\n * @returns A new function that applies all functions from right to left.\n *\n * @example\n * ```ts\n * const add = (x: number) => x + 1;\n * const double = (x: number) => x * 2;\n * const toStr = (x: number) => `Result: ${x}`;\n *\n * const result = compose(toStr, double, add)(2);\n * // => 'Result: 6'\n * ```\n */\nexport const compose: Compose =\n (...fns: ComposeFn[]) =>\n (arg: unknown) =>\n fns.reduceRight((prev, fn) => fn(prev), arg);\n","export const noop = () => {};\n\n/**\n * Checks if a value is a function.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a function; otherwise, `false`.\n */\nexport const isFunction = (value: unknown) => typeof value === 'function';\n\n/**\n * Creates a function that negates the result of the given predicate function.\n *\n * @template Args - Argument types of the predicate function.\n *\n * @param fn - A function that returns any value.\n *\n * @returns A new function that returns the negated result of the original function.\n *\n * @example\n * ```ts\n * const isEven = (n: number) => n % 2 === 0;\n * const isOdd = not(isEven);\n *\n * console.log(isOdd(2)); // false\n * console.log(isOdd(3)); // true\n * ```\n */\nexport const not =\n <Args extends unknown[]>(fn: (...args: Args) => any): ((...args: Args) => boolean) =>\n (...args: Args) =>\n !fn(...args);\n\n/**\n * Wraps a function so that it can only be executed once.\n * The wrapped function remembers (caches) the result of the first invocation\n * and returns that same result for all subsequent calls, regardless of the arguments provided.\n *\n * Common use cases include:\n * - initializing singletons\n * - running setup logic only once\n * - avoiding repeated expensive computations\n *\n * @template T - A function type whose return value should be cached.\n *\n * @param fn - The function to execute at most once.\n *\n * @returns A new function with the same signature as `fn`, but guaranteed to\n * execute `fn` only on the first call and return the cached result\n * thereafter.\n */\nexport const once = <T extends (...args: any[]) => any>(fn: T): T => {\n let called = false;\n let result: ReturnType<T>;\n\n return function (this: any, ...args: Parameters<T>) {\n if (!called) {\n called = true;\n result = fn.apply(this, args);\n }\n\n return result;\n } as T;\n};\n","import type { Nullable } from '~/types';\nimport { compact } from '~/array';\nimport { isFunction } from '~/function';\n\n/**\n * Checks if a value is a Promise.\n *\n * @template T - The type of the value that the Promise resolves to.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Promise; otherwise, `false`.\n */\nexport const isPromise = <T = unknown>(value: unknown): value is Promise<T> =>\n isFunction((value as Promise<T>)?.then);\n\n/**\n * Asynchronously iterates over an array and executes an async function on each item sequentially,\n * collecting the results.\n *\n * Useful when order or timing matters (e.g., rate limits, UI updates, animations).\n *\n * @param array - The array of items to iterate over.\n * @param fn - An async function to execute for each item. Must return a value.\n *\n * @returns A promise that resolves with an array of results from each function call.\n *\n * @example\n * ```ts\n * const results = await runSequential([1, 2, 3], async (item) => {\n * await delay(100);\n *\n * return item * 2;\n * });\n *\n * console.log(results); // [2, 4, 6]\n * ```\n */\nexport const runSequential = async <Item, Result>(\n array: Item[],\n fn: (item: Item, index: number, array: Item[]) => Promise<Result>,\n): Promise<Result[]> => {\n const results: Result[] = [];\n\n for (let i = 0; i < array.length; i++) {\n results.push(await fn(array[i], i, array));\n }\n\n return results;\n};\n\n/**\n * Executes an asynchronous operation on each element of an array and waits for all promises to resolve.\n *\n * @param array - The array of items to operate on.\n * @param fn - The asynchronous operation to perform on each item.\n *\n * @returns A promise that resolves with an array of results after all operations are completed.\n *\n * @example\n * ```ts\n * const results = await runParallel([1, 2, 3], async (item) => {\n * await delay(100);\n *\n * return item * 2;\n * });\n *\n * console.log(results); // [2, 4, 6]\n * ```\n */\nexport const runParallel = async <Item, Result>(\n array: Item[],\n fn: (item: Item, index: number, array: Item[]) => Promise<Result>,\n): Promise<Result[]> => Promise.all(array.map(fn));\n\n/**\n * Asynchronously filters an array using a predicate function, executing **sequentially**.\n *\n * Useful for rate-limited or stateful async operations where execution order matters.\n *\n * @template Item - The type of the items in the input array.\n *\n * @param array - The array of items to filter.\n * @param predicate - An async function that returns a `boolean` indicating whether to keep each item.\n *\n * @returns A promise that resolves to a new array containing only the items for which the predicate returned `true`.\n *\n * @example\n * ```ts\n * // Sequentially filter even numbers with delay\n * const result = await filterSequential([1, 2, 3, 4], async (num) => {\n * await delay(100);\n *\n * return num % 2 === 0;\n * });\n *\n * console.log(result); // [2, 4]\n * ```\n */\nexport const filterSequential = async <Item>(\n array: Item[],\n predicate: (item: Item, index: number, array: Item[]) => Promise<boolean>,\n): Promise<Item[]> => {\n const results: Item[] = [];\n\n for (let i = 0; i < array.length; i++) {\n const item = array[i];\n\n if (await predicate(item, i, array)) {\n results.push(item);\n }\n }\n\n return results;\n};\n\n/**\n * Asynchronously filters an array based on a provided async predicate function.\n *\n * Each item is passed to the `predicate` function in parallel, and only the items\n * for which the predicate resolves to `true` are included in the final result.\n *\n * Useful for filtering based on asynchronous conditions such as API calls,\n * file system access, or any other delayed operations.\n *\n * @template Item - The type of the items in the input array.\n *\n * @param array - The array of items to filter.\n * @param predicate - An async function that returns a boolean indicating whether to keep each item.\n *\n * @returns A promise that resolves to a new array containing only the items for which the predicate returned `true`.\n *\n * @example\n * ```ts\n * // Filter numbers that are even after a simulated delay\n * const result = await filterParallel([1, 2, 3, 4], async (num) => {\n * await delay(100);\n *\n * return num % 2 === 0;\n * });\n *\n * console.log(result); // [2, 4]\n * ```\n */\nexport const filterParallel = async <Item>(\n array: Item[],\n predicate: (item: Item, index: number, array: Item[]) => Promise<boolean>,\n): Promise<Item[]> => {\n const results = await runParallel(array, async (item, index, array) =>\n (await predicate(item, index, array)) ? item : false,\n );\n\n return compact(results);\n};\n\n/**\n * Asynchronously checks if at least one element in the array satisfies the async condition.\n *\n * @param array - The array of items to check.\n * @param predicate - An async function that returns a boolean.\n *\n * @returns A promise that resolves to true if any item passes the condition.\n */\nexport const someAsync = async <Item>(\n array: Item[],\n predicate: (item: Item, index: number, array: Item[]) => Promise<boolean>,\n): Promise<boolean> => {\n for (let i = 0; i < array.length; i++) {\n if (await predicate(array[i], i, array)) {\n return true;\n }\n }\n\n return false;\n};\n\n/**\n * Asynchronously checks if all elements in the array satisfy the async condition.\n *\n * @param array - The array of items to check.\n * @param predicate - An async function that returns a boolean.\n *\n * @returns A promise that resolves to true if all items pass the condition.\n */\nexport const everyAsync = async <Item>(\n array: Item[],\n predicate: (item: Item, index: number, array: Item[]) => Promise<boolean>,\n): Promise<boolean> => {\n for (let i = 0; i < array.length; i++) {\n if (!(await predicate(array[i], i, array))) {\n return false;\n }\n }\n\n return true;\n};\n\n/**\n * Asynchronously reduces an array to a single accumulated value.\n *\n * @template Item - The type of items in the array.\n * @template Accumulator - The type of the accumulated result.\n *\n * @param array - The array to reduce.\n * @param fn - The async reducer function that processes each item and returns the updated accumulator.\n * @param initialValue - The initial accumulator value.\n *\n * @returns A promise that resolves to the final accumulated result.\n */\nexport const reduceAsync = async <Item, Accumulator>(\n array: Item[],\n fn: (accumulator: Accumulator, item: Item, index: number, array: Item[]) => Promise<Accumulator>,\n initialValue: Accumulator,\n): Promise<Accumulator> => {\n let accumulator = initialValue;\n\n for (let i = 0; i < array.length; i++) {\n accumulator = await fn(accumulator, array[i], i, array);\n }\n\n return accumulator;\n};\n\n/**\n * Asynchronously finds the first element that satisfies the async condition.\n *\n * @param array - The array of items to search.\n * @param predicate - An async function that returns a boolean.\n *\n * @returns A promise that resolves to the found item or null if none match.\n */\nexport const findAsync = async <Item>(\n array: Item[],\n predicate: (item: Item, index: number, array: Item[]) => Promise<boolean>,\n): Promise<Nullable<Item>> => {\n for (let i = 0; i < array.length; i++) {\n if (await predicate(array[i], i, array)) {\n return array[i];\n }\n }\n\n return null;\n};\n","/**\n * Creates a promise that resolves after the specified delay.\n *\n * Useful for creating artificial delays, implementing timeouts, or spacing operations.\n *\n * @param delayMs - The delay in milliseconds.\n *\n * @returns A promise that resolves after the specified delay.\n *\n * @example\n * ```ts\n * // Wait for 1 second\n * await delay(1000);\n * console.log('This logs after 1 second');\n *\n * // Use with other async operations\n * const fetchWithTimeout = async () => {\n * const timeoutPromise = delay(5000).then(() => {\n * throw new Error('Request timed out');\n * });\n *\n * return Promise.race([fetchData(), timeoutPromise]);\n * }\n * ```\n */\nexport const delay = (delayMs: number): Promise<void> =>\n new Promise(resolve => setTimeout(resolve, delayMs));\n","import type { Nullable, TimeoutId } from '~/types';\nimport { delay } from '~/async';\n\n/**\n * Wraps a promise with a timeout. If the promise does not settle within the specified time,\n * it will reject with a timeout error.\n *\n * @template T - The type of the promise result.\n *\n * @param promise - The promise to wrap.\n * @param timeoutMs - Timeout duration in milliseconds.\n * @param errorMessage - Optional custom error message.\n *\n * @returns A promise that resolves or rejects with the original promise,\n * or rejects with a timeout error if the duration is exceeded.\n *\n * @example\n * ```ts\n * // Rejects if fetch takes longer than 3 seconds\n * const response = await timeout(fetch('/api/data'), 3000);\n *\n * // With custom message\n * await timeout(fetchData(), 2000, 'Too long');\n * ```\n */\nexport const timeout = async <T>(\n promise: Promise<T>,\n timeoutMs: number,\n errorMessage = 'Operation timed out',\n): Promise<T> => {\n const timeoutId: Nullable<TimeoutId> = null;\n\n try {\n return await Promise.race([\n promise,\n delay(timeoutMs).then(() => Promise.reject(new Error(errorMessage))),\n ]);\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n};\n","import { delay } from '~/async';\n\ninterface RetryOptions {\n /**\n * Maximum number of retry attempts before failing.\n *\n * @default 3\n */\n maxAttempts?: number;\n /**\n * Delay in milliseconds between retry attempts.\n * If `backoff` is true, this is the base delay for exponential backoff.\n *\n * @default 300\n */\n delayMs?: number;\n /**\n * Whether to use exponential backoff for delays between attempts.\n * When enabled, the delay is multiplied by 2 ^ (`attempt` - 1).\n *\n * @default true\n */\n backoff?: boolean;\n /**\n * Optional callback triggered before each retry attempt.\n *\n * @param attempt - The current attempt number (starting from 1).\n * @param error - The error that caused the retry.\n */\n onRetry?: (attempt: number, error: unknown) => void;\n}\n\n/**\n * Wraps an asynchronous function with retry logic.\n *\n * The returned function will attempt to call the original function up to `maxAttempts` times,\n * with a delay between retries. If all attempts fail, the last encountered error is thrown.\n *\n * Useful for operations that may fail intermittently, such as network requests.\n *\n * @template Task - The type of the async function to wrap.\n * @template TaskResult - The result type of the async function.\n *\n * @param task - The async function to wrap with retry logic.\n * @param options - Configuration options for retry behavior.\n *\n * @returns A function that wraps the original function with retry support.\n *\n * @example\n * ```ts\n * async function fetchData() {\n * const response = await fetch('/api/data');\n *\n * if (!response.ok) {\n * throw new Error('Network error');\n * }\n *\n * return await response.json();\n * }\n *\n * const fetchWithRetry = retry(fetchData, {\n * maxAttempts: 5,\n * delayMs: 500,\n * onRetry: (attempt, error) => {\n * console.warn(`Attempt ${attempt} failed:`, error);\n * }\n * });\n *\n * fetchWithRetry()\n * .then(data => console.log('Success:', data))\n * .catch(error => console.error('Failed after retries:', error));\n * ```\n */\nexport const retry = <Task extends (...args: unknown[]) => Promise<TaskResult>, TaskResult>(\n task: Task,\n { maxAttempts = 3, delayMs = 300, backoff = true, onRetry }: RetryOptions = {},\n): ((...args: Parameters<Task>) => Promise<TaskResult>) => {\n return async (...args: Parameters<Task>): Promise<TaskResult> => {\n let lastError: unknown;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await task(...args);\n } catch (e) {\n lastError = e;\n\n if (attempt < maxAttempts) {\n onRetry?.(attempt, e);\n\n const delayTime = backoff ? delayMs * 2 ** (attempt - 1) : delayMs;\n await delay(delayTime);\n }\n }\n }\n\n throw lastError;\n };\n};\n","/**\n * Checks if a value is a string.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a string; otherwise, `false`.\n */\nexport const isString = (value: unknown): value is string => typeof value === 'string';\n","import { isString } from '~/string';\nimport { assert, isUndefined } from '~/guards';\n\nexport type Downloadable = Blob | MediaSource | string;\n\nexport interface DownloadFileOptions {\n /**\n * Suggested filename for the downloaded file.\n *\n * When provided, the browser will attempt to save the file using this name.\n * If omitted and the source is a URL string, the browser may infer the name\n * from the URL.\n */\n fileName?: string;\n /**\n * Target browsing context for the download link.\n */\n target?: '_self' | '_blank';\n}\n\n/**\n * Initiates a file download in a browser environment.\n *\n * This utility supports downloading from:\n * - a URL string\n * - a `Blob`\n * - a `MediaSource`\n *\n * For non-string inputs, an object URL is created temporarily and\n * automatically revoked after the download is triggered.\n *\n * @remarks\n * - This function performs direct DOM manipulation and must be executed in a browser environment.\n * - In non-DOM contexts (e.g. SSR), the function exits without side effects.\n * - Object URLs are revoked asynchronously to avoid Safari-related issues.\n *\n * @param file - The file source to download (URL string or binary object).\n * @param options - Optional configuration controlling filename and link target.\n */\nexport const downloadFile = (\n file: Downloadable,\n { fileName, target }: DownloadFileOptions = {},\n): void => {\n // Browser guard (SSR / non-DOM environments)\n if (isUndefined(document)) {\n return;\n }\n\n const link = document.createElement('a');\n let objectUrl: string | null = null;\n\n try {\n const href = isString(file) ? file : (objectUrl = URL.createObjectURL(file));\n link.href = href;\n\n if (fileName) {\n link.download = fileName;\n }\n\n if (target) {\n link.target = target;\n }\n\n // Required for Firefox / Safari\n document.body.appendChild(link);\n link.click();\n } finally {\n link.remove();\n\n if (objectUrl) {\n // Delay revocation to avoid Safari issues\n setTimeout(() => {\n assert(objectUrl, 'Object URL should not be null');\n\n URL.revokeObjectURL(objectUrl);\n }, 0);\n }\n }\n};\n","/**\n * Checks whether an element has horizontal overflow.\n *\n * @param element - The element to check.\n *\n * @returns `true` if the content overflows horizontally.\n */\nexport const hasXOverflow = (element: HTMLElement): boolean =>\n element.scrollWidth > element.clientWidth;\n\n/**\n * Calculates the horizontal overflow width of an element.\n *\n * The overflow width represents how much wider the content is compared\n * to the visible container area.\n *\n * @param element - The scrollable container element.\n *\n * @returns The overflow width in pixels. Returns `0` when the content does not overflow horizontally.\n */\nexport const getXOverflowWidth = (element: HTMLElement): number =>\n Math.max(0, element.scrollWidth - element.clientWidth);\n\n/**\n * Checks whether an element has vertical overflow.\n *\n * @param element - The element to check.\n *\n * @returns `true` if the content overflows vertically.\n */\nexport const hasYOverflow = (element: HTMLElement): boolean =>\n element.scrollHeight > element.clientHeight;\n\n/**\n * Calculates the vertical overflow height of an element.\n *\n * The overflow height represents how much taller the content is compared\n * to the visible container area.\n *\n * @param element - The scrollable container element.\n *\n * @returns The overflow height in pixels. Returns `0` when the content does not overflow vertically.\n */\nexport const getYOverflowHeight = (element: HTMLElement): number =>\n Math.max(0, element.scrollHeight - element.clientHeight);\n","export interface CalculateCenterOffsetOptions {\n /**\n * Total overflow size for the axis.\n *\n * Represents how much larger the content is compared to the visible\n * container size (e.g. scroll width minus client width).\n */\n overflowSize: number;\n /**\n * Visible size of the container along the axis.\n *\n * Typically, `clientWidth` for the X axis or `clientHeight` for the Y axis.\n */\n containerSize: number;\n /**\n * Offset of the target element from the start of the container along the axis.\n *\n * Typically, `offsetLeft` (X axis) or `offsetTop` (Y axis).\n */\n elementOffset: number;\n /**\n * Size of the target element along the axis.\n *\n * Typically, `clientWidth` (X axis) or `clientHeight` (Y axis).\n */\n elementSize: number;\n}\n\n/**\n * Calculates the offset required to center an element within a container along a single axis.\n *\n * The returned value is clamped so that the resulting translation does not\n * exceed the container's scrollable bounds.\n *\n * This function performs pure math only and does not access the DOM.\n *\n * @returns A negative offset value suitable for use in a CSS `translate`\n * transform, or `0` when no overflow exists on the axis.\n */\nexport const calculateCenterOffset = ({\n overflowSize,\n containerSize,\n elementOffset,\n elementSize,\n}: CalculateCenterOffsetOptions): number => {\n if (overflowSize <= 0) {\n return 0;\n }\n\n const containerCenter = containerSize / 2;\n const elementCenter = elementOffset + elementSize / 2;\n\n const targetOffset = elementCenter - containerCenter;\n\n return -Math.max(0, Math.min(targetOffset, overflowSize));\n};\n","import { getXOverflowWidth, getYOverflowHeight } from '~/dom';\nimport { calculateCenterOffset } from '~/geometry';\n\ntype Axis = 'x' | 'y' | 'both';\n\nexport interface CenterElementInContainerOptions {\n /**\n * Axis (or axes) along which centering is applied.\n *\n * @default 'both'\n */\n axis?: Axis;\n}\n\n/**\n * Translates a container so that a target element is visually centered within its visible bounds.\n *\n * Centering is achieved by applying a CSS `transform: translate(...)` to the\n * container element rather than using native scrolling.\n *\n * ### Behavior\n * - Centering is calculated independently for each enabled axis.\n * - Translation is applied only when the container content overflows on that axis.\n * - When no overflow exists, the container remains untransformed for that axis.\n *\n * ### Notes\n * - This function performs immediate DOM reads and writes.\n * - The resulting transform is clamped to valid scrollable bounds.\n *\n * @param containerElement - The container whose content is translated.\n * @param elementToCenter - The descendant element to align to the container’s center.\n * @param options - Optional configuration controlling which axis or axes are centered.\n */\nexport const centerElementInContainer = (\n containerElement: HTMLElement,\n elementToCenter: HTMLElement,\n { axis = 'both' }: CenterElementInContainerOptions = {},\n): void => {\n let translateX = 0;\n let translateY = 0;\n\n if (axis === 'x' || axis === 'both') {\n translateX = calculateCenterOffset({\n overflowSize: getXOverflowWidth(containerElement),\n containerSize: containerElement.clientWidth,\n elementOffset: elementToCenter.offsetLeft,\n elementSize: elementToCenter.clientWidth,\n });\n }\n\n if (axis === 'y' || axis === 'both') {\n translateY = calculateCenterOffset({\n overflowSize: getYOverflowHeight(containerElement),\n containerSize: containerElement.clientHeight,\n elementOffset: elementToCenter.offsetTop,\n elementSize: elementToCenter.clientHeight,\n });\n }\n\n containerElement.style.transform = `translate(${translateX}px, ${translateY}px)`;\n};\n","interface HTMLElementTransformationValues {\n translateX: number;\n translateY: number;\n scaleX: number;\n scaleY: number;\n skewX: number;\n skewY: number;\n}\n\n/**\n * Extracts transformation values (translate, scale, skew) from the 2D transformation matrix of a given HTML element.\n *\n * Only works with 2D transforms (i.e., `matrix(a, b, c, d, e, f)`).\n *\n * @param element - The element with a CSS transform applied.\n * @returns An object with parsed transformation values.\n *\n * @example\n * ```ts\n * const values = parse2DMatrix(myElement);\n * console.log(values.translateX);\n * console.log(values.scaleX);\n * ```\n */\nexport const parse2DMatrix = (element: HTMLElement): HTMLElementTransformationValues => {\n const computedStyles = window.getComputedStyle(element);\n const transformValue = computedStyles.getPropertyValue('transform');\n\n const matrixMatch = transformValue.match(/^matrix\\((.+)\\)$/);\n if (!matrixMatch) {\n return {\n translateX: 0,\n translateY: 0,\n scaleX: 1,\n scaleY: 1,\n skewX: 0,\n skewY: 0,\n };\n }\n\n const [scaleX, skewY, skewX, scaleY, translateX, translateY] = matrixMatch[1]\n .split(', ')\n .map(parseFloat);\n\n return {\n translateX,\n translateY,\n scaleX,\n scaleY,\n skewX,\n skewY,\n };\n};\n","/**\n * Determines whether the browser environment allows safe read access to\n * `localStorage`. Some platforms (e.g., Safari Private Mode, sandboxed iframes)\n * expose `localStorage` but still throw when accessed.\n *\n * This function **only tests read access**, making it safe even when write\n * operations would fail due to `QuotaExceededError` or storage restrictions.\n *\n * @returns `true` if `localStorage` exists and calling `getItem()` does not\n * throw; otherwise `false`.\n */\nexport const isLocalStorageReadable = (): boolean => {\n if (typeof window === 'undefined' || !window.localStorage) {\n return false;\n }\n\n try {\n window.localStorage.getItem('__non_existing_key__');\n return true;\n } catch {\n return false;\n }\n};\n\ninterface LocalStorageCapabilities {\n readable: boolean;\n writable: boolean;\n}\n\ninterface LocalStorageCapabilities {\n readable: boolean;\n writable: boolean;\n}\n\n/**\n * Determines whether the browser's `localStorage` supports safe read and write operations.\n * This function performs two independent checks:\n *\n * **1. Readability**\n * - Verified by calling `localStorage.getItem()` inside a `try` block.\n * - Fails in environments where storage access throws immediately (e.g., disabled storage,\n * sandboxed iframes, strict privacy modes, SSR).\n *\n * **2. Writeability**\n * - Verified by attempting to `setItem()` and then `removeItem()` using a temporary key.\n * - Can fail due to:\n * - `QuotaExceededError` when storage is full.\n * - Disabled write access (e.g., Safari Private Mode).\n * - Security-restricted contexts (third-party frames, hardened privacy settings)\n *\n * @returns An object describing the detected `localStorage` capabilities.\n */\nexport const getLocalStorageCapabilities = (): LocalStorageCapabilities => {\n const readable = isLocalStorageReadable();\n if (!readable) {\n return {\n readable: false,\n writable: false,\n };\n }\n\n try {\n const key = '__test_write__';\n\n window.localStorage.setItem(key, '1');\n window.localStorage.removeItem(key);\n\n return {\n readable: true,\n writable: true,\n };\n } catch {\n // Readable but not writable (QuotaExceededError, private mode, security restrictions)\n }\n\n return {\n readable: true,\n writable: false,\n };\n};\n","import type { Nullable } from '~/types';\nimport { runParallel } from '~/async';\n\n/**\n * Checks if a value is a `File` object.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a `File` object; otherwise, `false`.\n */\nexport const isFile = (value: unknown): value is File => value instanceof File;\n\n/**\n * Converts a `FileList` object to an array of `File` objects.\n *\n * @param fileList - The `FileList` object to convert.\n *\n * @returns An array of `File` objects.\n */\nexport const fileListToFiles = (fileList: Nullable<FileList>): File[] => {\n if (!fileList) {\n return [];\n }\n\n const files: File[] = [];\n\n for (let i = 0; i < fileList.length; i++) {\n files.push(fileList[i]);\n }\n\n return files;\n};\n\n/**\n * Converts a `Blob` object into a `File` object with the specified name.\n *\n * This is useful when you receive a `Blob` (e.g., from canvas, fetch, or file manipulation)\n * and need to convert it into a `File` to upload via `FormData` or file inputs.\n *\n * @param blob - The `Blob` to convert.\n * @param fileName - The desired name for the resulting file (including extension).\n *\n * @returns A `File` instance with the same content and MIME type as the input `Blob`.\n *\n * @example\n * ```ts\n * const blob = new Blob(['Hello world'], { type: 'text/plain' });\n * const file = blobToFile(blob, 'hello.txt');\n *\n * console.log(file instanceof File); // true\n * ```\n */\nexport const blobToFile = (blob: Blob, fileName: string): File =>\n new File([blob], fileName, {\n type: blob.type,\n });\n\n/**\n * Reads all entries from a file system directory asynchronously.\n *\n * @param directoryEntry - The directory entry to read.\n *\n * @returns A promise that resolves to all `FileSystemEntry` items in the directory.\n */\nconst readFileSystemDirectoryEntries = async (\n directoryEntry: FileSystemDirectoryEntry,\n): Promise<FileSystemEntry[]> => {\n const directoryReader = directoryEntry.createReader();\n\n const readAll = async (): Promise<FileSystemEntry[]> =>\n new Promise((resolve, reject) => {\n directoryReader.readEntries(async entries => {\n if (!entries.length) {\n resolve([]);\n return;\n }\n\n try {\n const restEntries = await readAll();\n\n resolve([...entries, ...restEntries]);\n } catch (e) {\n reject(e);\n }\n }, reject);\n });\n\n return readAll();\n};\n\ninterface TraverseDirectoryOptions {\n /**\n * A list of file names that should be ignored during traversal.\n * Any file whose name matches an entry will be skipped entirely.\n *\n * Common values include OS-generated metadata files such as:\n * `.DS_Store`, `Thumbs.db`, `desktop.ini`, `.Spotlight-V100`, etc.\n */\n skipFiles?: string[];\n}\n\n/**\n * Recursively scans a directory using the File System API and collects all nested files.\n *\n * This function walks through all subdirectories, resolving each file into a `File` object.\n * Directories themselves are not returned. To avoid unnecessary noise, certain system or\n * OS-generated files can be excluded via the `skipFiles` option.\n *\n * @param directoryEntry - The starting directory entry to traverse.\n * @param options - Optional settings that control traversal behavior.\n *\n * @returns A promise resolving to a flat array of all collected `File` objects.\n */\nexport const traverseFileSystemDirectory = async (\n directoryEntry: FileSystemDirectoryEntry,\n {\n skipFiles = [\n '.DS_Store',\n 'Thumbs.db',\n 'desktop.ini',\n 'ehthumbs.db',\n '.Spotlight-V100',\n '.Trashes',\n '.fseventsd',\n '__MACOSX',\n ],\n }: TraverseDirectoryOptions = {},\n): Promise<File[]> => {\n const skipFilesSet = new Set(skipFiles);\n const entries = await readFileSystemDirectoryEntries(directoryEntry);\n\n const filePromises = await runParallel(entries, async entry => {\n if (entry.isDirectory) {\n return traverseFileSystemDirectory(entry as FileSystemDirectoryEntry, {\n skipFiles,\n });\n } else if (!skipFilesSet.has(entry.name)) {\n const file = await new Promise<File>((resolve, reject) => {\n (entry as FileSystemFileEntry).file(resolve, reject);\n });\n\n return [file];\n }\n\n return [];\n });\n\n return filePromises.flat();\n};\n\n/**\n * Reads files from a `DataTransfer` object, supporting both individual files\n * and entire directories (when available through the non-standard `webkitGetAsEntry` API).\n *\n * This function is typically used in drag-and-drop or paste handlers to obtain\n * all `File` objects contained in the user's action. When directories are dropped,\n * they are traversed recursively using `traverseFileSystemDirectory`, returning a\n * fully flattened list of nested files.\n *\n * @param dataTransfer - The `DataTransfer` instance from a drop or paste event.\n * If `null` or missing items, an empty array is returned.\n * @param traverseOptions - Optional settings passed to directory traversal.\n *\n * @returns A promise that resolves to a flat array of all extracted `File` objects.\n * This includes:\n * - direct files from the drag event,\n * - files extracted from directory entries via `webkitGetAsEntry`,\n * - and files found recursively within nested subdirectories.\n */\nexport const readFilesFromDataTransfer = async (\n dataTransfer: Nullable<DataTransfer>,\n traverseOptions: TraverseDirectoryOptions = {},\n) => {\n const items = dataTransfer?.items;\n if (!items) {\n return [];\n }\n\n const tasks: Promise<File[]>[] = [];\n\n for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {\n const item = items[itemIndex];\n\n // Prefer using webkitGetAsEntry when available (directory support)\n // https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/webkitGetAsEntry#browser_compatibility\n if ('webkitGetAsEntry' in item) {\n // ?.() -> avoids throwing on Safari weirdness\n const entry = item.webkitGetAsEntry?.();\n\n if (entry?.isDirectory) {\n tasks.push(traverseFileSystemDirectory(entry as FileSystemDirectoryEntry, traverseOptions));\n\n continue;\n }\n\n if (entry?.isFile) {\n tasks.push(\n new Promise<File[]>((resolve, reject) =>\n (entry as FileSystemFileEntry).file(file => resolve([file]), reject),\n ),\n );\n\n continue;\n }\n }\n\n // Fallback to standard API\n const file = item.getAsFile();\n if (file) {\n tasks.push(Promise.resolve([file]));\n }\n }\n\n return (await Promise.all(tasks)).flat();\n};\n","/**\n * Invokes the given input if it is a function, passing the provided arguments.\n * Otherwise, returns the input as-is.\n *\n * @template Args - Tuple of argument types to pass to the function.\n * @template Result - Return type of the function or the value.\n *\n * @param input - A function to invoke with `args`, or a direct value of type `Result`.\n * @param args - Arguments to pass if `input` is a function.\n *\n * @returns The result of invoking the function, or the original value if it's not a function.\n */\nexport const invokeIfFunction = <Args extends unknown[], Result>(\n input: ((...args: Args) => Result) | Result,\n ...args: Args\n): Result => (typeof input === 'function' ? (input as (...args: Args) => Result)(...args) : input);\n","import type { Nullable } from '~/types';\n\ninterface ResolveBoundedDeltaOptions {\n /**\n * Incremental change to apply to the current value.\n *\n * The sign of this value determines the direction of movement:\n * - Negative values move toward the minimum bound\n * - Positive values move toward the maximum bound\n */\n delta: number;\n /**\n * Current numeric value before applying the delta.\n */\n value: number;\n /**\n * Minimum allowed value (inclusive).\n *\n * Movement beyond this boundary is prevented.\n */\n min: number;\n /**\n * Maximum allowed value (inclusive).\n *\n * Movement beyond this boundary is prevented.\n */\n max: number;\n}\n\n/**\n * Resolves the next value by consuming a delta within fixed numeric bounds.\n *\n * This function applies **bounded delta consumption** rather than naive clamping:\n *\n * - The delta is applied in the given direction as long as movement is possible.\n * - If the delta would overshoot a bound, it is partially consumed so the\n * resulting value lands exactly on the boundary.\n * - If movement in the given direction is no longer possible, `null` is returned.\n *\n * This behavior mirrors how native scroll engines and drag constraints\n * handle fast input without jitter or overshoot.\n *\n * ### Key characteristics\n * - Direction-aware (positive and negative deltas behave independently)\n * - Prevents overshoot while preserving remaining movement\n * - Does **not** clamp unconditionally\n * - Side-effect free and fully deterministic\n *\n * ### Common use cases\n * - Synthetic scrolling\n * - Drag constraints\n * - Sliders and carousels\n * - Timelines and scrubbers\n * - Inertia and momentum systems\n *\n * @param delta - Incremental change to apply to the current value.\n * The sign determines the movement direction.\n * @param value - Current numeric value before applying the delta.\n * @param min - Minimum allowed value (inclusive).\n * @param max - Maximum allowed value (inclusive).\n *\n * @returns The next resolved value after applying the delta,\n * or `null` if movement in the given direction is not possible.\n *\n * @example\n * ```ts\n * // Simple bounded movement\n * resolveBoundedDelta({ value: 10, delta: -5, min: 0, max: 100 });\n * // → 5\n *\n * // Overshoot is clamped to the boundary\n * resolveBoundedDelta({ value: 2, delta: -10, min: 0, max: 100 });\n * // → 0\n *\n * // Movement blocked at the boundary\n * resolveBoundedDelta({ value: 0, delta: -5, min: 0, max: 100 });\n * // → null\n * ```\n */\nexport const resolveBoundedDelta = ({\n delta,\n value,\n min,\n max,\n}: ResolveBoundedDeltaOptions): Nullable<number> => {\n if (delta === 0) {\n return null;\n }\n\n const candidate = value + delta;\n\n if (delta < 0) {\n return value <= min ? null : Math.max(candidate, min);\n }\n\n if (delta > 0) {\n return value >= max ? null : Math.min(candidate, max);\n }\n\n return null;\n};\n","import type { Nullable } from '~/types';\nimport { resolveBoundedDelta } from '~/geometry';\n\nexport interface InertiaOptions {\n /**\n * Current velocity of the inertial motion.\n *\n * Expressed in **pixels per millisecond (`px/ms`)**.\n *\n * The sign determines direction:\n * - Positive → movement toward the upper bound\n * - Negative → movement toward the lower bound\n */\n velocityPxMs: number;\n /**\n * Time elapsed since the previous inertia step, in milliseconds.\n */\n deltaTimeMs: number;\n /**\n * Exponential friction coefficient controlling velocity decay.\n *\n * Friction is applied per millisecond using an exponential model:\n *\n * `velocityPxMs *= exp(-friction * deltaTimeMs)`\n *\n * Smaller values result in longer, floatier inertia;\n * larger values cause quicker deceleration.\n *\n * Typical values:\n * - `0.001` — very long, floaty inertia\n * - `0.002` — balanced, natural decay (default)\n * - `0.005` — short, snappy stop\n *\n * @default 0.002\n */\n friction?: number;\n /**\n * Minimum absolute velocity below which inertia is considered complete.\n *\n * When `|velocityPxMs| < minVelocityPxMs`, inertia terminates and no further movement is applied.\n *\n * This prevents unnecessary micro-updates and visual jitter near rest.\n *\n * @default 0.01\n */\n minVelocityPxMs?: number;\n /**\n * Exponential Moving Average (EMA) factor used to smooth velocity changes.\n *\n * This is applied **after friction**, blending the previous velocity\n * with the newly decayed velocity to reduce jitter and sudden spikes.\n *\n * Value range: `0..1`\n *\n * - `0` → EMA disabled (raw exponential decay only)\n * - `0.2` → light smoothing (recommended for scroll / drag inertia)\n * - `0.5` → heavy smoothing (very soft, less responsive)\n *\n * Formula:\n * `vNext = vPrev * (1 - emaAlpha) + vDecayed * emaAlpha`\n *\n * @default 0.2\n */\n emaAlpha?: number;\n}\n\ninterface ApplyInertiaStepOptions extends InertiaOptions {\n /**\n * Current numeric value before applying the inertia step.\n *\n * This commonly represents a translated position\n * (e.g. scroll offset or `translateX` value),\n * but may be any numeric value constrained by bounds.\n */\n value: number;\n /**\n * Lower bound for the value (inclusive).\n */\n min: number;\n /**\n * Upper bound for the value (inclusive).\n */\n max: number;\n}\n\n/**\n * Result of a single inertia simulation step.\n *\n * Returned when inertia is still active and further movement in the current direction is possible.\n */\nexport interface InertiaStepResult {\n /**\n * Updated value after applying this inertia step.\n *\n * Guaranteed to be within `[min, max]`.\n */\n value: number;\n /**\n * Updated velocity after friction decay and optional EMA smoothing.\n *\n * Expressed in pixels per millisecond (`px/ms`).\n */\n velocityPxMs: number;\n}\n\n/**\n * Applies a **single step** of bounded, velocity-based inertia.\n *\n * This function models **momentum-driven motion** by:\n * - integrating velocity over elapsed time\n * - applying exponential friction\n * - optionally smoothing velocity using EMA\n * - enforcing hard bounds via {@link resolveBoundedDelta}\n *\n * Boundary handling guarantees:\n * - no overshoot\n * - no oscillation at limits\n * - deterministic stopping behavior\n *\n * ---\n *\n * ### Termination conditions\n * Inertia ends immediately when:\n * - the absolute velocity falls below `minVelocityPxMs`, or\n * - movement in the current direction is blocked by a bound\n *\n * ---\n *\n * ⚠️ **Single-step function**\n * This function advances inertia **once only**.\n * It must be invoked repeatedly from an animation loop\n * (e.g. `requestAnimationFrame`) to produce continuous motion.\n *\n * ---\n *\n * ### Common use cases\n * - Synthetic scrolling with momentum\n * - Drag-to-scroll interactions\n * - Carousels and sliders\n * - Timelines and scrubbers\n *\n * @returns An {@link InertiaStepResult} while inertia remains active,\n * or `null` when inertia has completed or cannot proceed.\n */\nexport const applyInertiaStep = ({\n value,\n min,\n max,\n velocityPxMs,\n deltaTimeMs,\n friction = 0.002,\n minVelocityPxMs = 0.01,\n emaAlpha = 0.2,\n}: ApplyInertiaStepOptions): Nullable<InertiaStepResult> => {\n if (Math.abs(velocityPxMs) < minVelocityPxMs) {\n return null;\n }\n\n const nextValue = resolveBoundedDelta({\n delta: velocityPxMs * deltaTimeMs,\n value,\n min,\n max,\n });\n\n // Hit a hard bound → stop inertia immediately\n if (nextValue === null) {\n return null;\n }\n\n /**\n * Apply exponential friction.\n * The exponent is **negative** because friction must continuously *reduce* velocity over time.\n */\n const decay = Math.exp(-friction * deltaTimeMs);\n const pureVelocityPxMs = velocityPxMs * decay;\n\n const nextVelocityPxMs =\n emaAlpha > 0 ? velocityPxMs * (1 - emaAlpha) + pureVelocityPxMs * emaAlpha : pureVelocityPxMs;\n\n if (Math.abs(nextVelocityPxMs) < minVelocityPxMs) {\n return null;\n }\n\n return {\n value: nextValue,\n velocityPxMs: nextVelocityPxMs,\n };\n};\n","/**\n * Generates a lightweight, ephemeral identifier for short-lived, client-side use.\n *\n * The identifier combines a high-resolution timestamp with a\n * pseudo-random suffix to reduce collision probability.\n *\n * ⚠️ Uniqueness is **best-effort only**:\n * - No guarantee of global uniqueness\n * - Not suitable for persistence or cross-session usage\n * - Not safe for security-sensitive or externally visible identifiers\n *\n * Intended use cases:\n * - Temporary UI keys (e.g. React lists, animations)\n * - In-memory references scoped to a single runtime\n *\n * @returns An ephemeral string identifier.\n */\nexport const generateEphemeralId = (): string => {\n const timestampPart = Math.floor(performance.now() * 1000).toString(36);\n const randomPart = Math.random().toString(36).slice(2, 10);\n\n return `${timestampPart}${randomPart}`;\n};\n","/**\n * Calculates the intersection ratio between two DOM rectangles.\n *\n * The ratio represents the proportion of the `targetRect` that is covered by `sourceRect`.\n * A value of `1` means `sourceRect` completely covers `targetRect`, and `0` means no overlap.\n *\n * @param sourceRect - The rectangle used to measure overlap against the target.\n * @param targetRect - The rectangle whose covered area is measured.\n *\n * @returns A number between `0` and `1` representing the intersection ratio.\n */\nexport const getDOMRectIntersectionRatio = (sourceRect: DOMRect, targetRect: DOMRect): number => {\n const xOverlap = Math.max(\n 0,\n Math.min(sourceRect.right, targetRect.right) - Math.max(sourceRect.left, targetRect.left),\n );\n\n const yOverlap = Math.max(\n 0,\n Math.min(sourceRect.bottom, targetRect.bottom) - Math.max(sourceRect.top, targetRect.top),\n );\n\n const intersectionArea = xOverlap * yOverlap;\n const targetArea = targetRect.width * targetRect.height;\n\n return intersectionArea / targetArea;\n};\n","export type Axis = 'x' | 'y' | 'both';\n\n/**\n * Values typically originate from wheel, drag, touch, or other pointer-based input sources.\n */\nexport interface AxisDelta {\n deltaX: number;\n deltaY: number;\n}\n\nexport interface ResolveAxisDeltaOptions {\n /**\n * Whether vertical input may be used as a fallback source\n * for horizontal movement when no horizontal delta is present.\n *\n * This is especially useful for mouse wheels that emit only\n * vertical deltas while scrolling horizontal content (e.g. tab lists or carousels).\n *\n * @default true\n */\n allowFallback?: boolean;\n /**\n * Whether to invert the resolved delta direction.\n *\n * Inversion is commonly required for synthetic scrolling,\n * where positive input deltas should move content in the\n * opposite direction of the pointer or wheel movement.\n *\n * @default true\n */\n invert?: boolean;\n}\n\n/**\n * Resolves a raw two-dimensional input delta into an axis-aligned delta\n * according to the specified axis and resolution rules.\n *\n * This function is input-agnostic and does not perform any DOM mutations.\n * It is intended to be used as a normalization step for wheel, drag,\n * touch, or other pointer-based input before applying scroll physics.\n *\n * ### Resolution rules\n * - `'x'`:\n * - Uses horizontal input when available.\n * - Optionally falls back to vertical input when horizontal input is zero.\n * - `'y'`:\n * - Uses vertical input only.\n * - `'both'`:\n * - Preserves both horizontal and vertical input.\n *\n * ### Direction handling\n * - When `invert` is enabled, the resolved delta direction is inverted\n * to match typical synthetic scrolling behavior.\n *\n * @param delta - Raw input movement delta.\n * @param axis - Axis along which movement should be resolved.\n * @param options - Resolution behavior configuration.\n *\n * @returns A normalized, axis-aligned delta suitable for further scroll or movement processing.\n */\nexport const resolveAxisDelta = (\n delta: AxisDelta,\n axis: Axis,\n { allowFallback = true, invert = true }: ResolveAxisDeltaOptions = {},\n): AxisDelta => {\n const sign = invert ? -1 : 1;\n\n switch (axis) {\n case 'x': {\n const value = delta.deltaX !== 0 ? delta.deltaX : allowFallback ? delta.deltaY : 0;\n\n return {\n deltaX: sign * value,\n deltaY: 0,\n };\n }\n\n case 'y':\n return {\n deltaX: 0,\n deltaY: sign * delta.deltaY,\n };\n\n default:\n return {\n deltaX: sign * delta.deltaX,\n deltaY: sign * delta.deltaY,\n };\n }\n};\n","/**\n * Calculates the Euclidean distance between two points in 2D space.\n *\n * @param startX - The X coordinate of the starting point.\n * @param startY - The Y coordinate of the starting point.\n * @param endX - The X coordinate of the ending point.\n * @param endY - The Y coordinate of the ending point.\n *\n * @returns The Euclidean distance between the two points.\n */\nexport const calculateEuclideanDistance = (\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n): number => {\n const deltaX = endX - startX;\n const deltaY = endY - startY;\n\n return Math.hypot(deltaX, deltaY);\n};\n\n/**\n * Calculates the moving speed.\n *\n * @param distance - The distance.\n * @param elapsedTime - The time taken to move the distance.\n *\n * @returns The calculated speed, which is the absolute value of delta divided by elapsed time.\n */\nexport const calculateMovingSpeed = (distance: number, elapsedTime: number): number =>\n Math.abs(distance / elapsedTime);\n\n/**\n * Calculates the specified percentage of a given value.\n *\n * @param value - The value to calculate the percentage of.\n * @param percentage - The percentage to calculate.\n *\n * @returns The calculated percentage of the value.\n */\nexport const calculatePercentage = (value: number, percentage: number): number =>\n (value * percentage) / 100;\n","/**\n * Generates a short, consistent hash string from an input string using a DJB2-inspired algorithm.\n *\n * This function uses a variation of the DJB2 algorithm, which is a simple yet effective hashing algorithm\n * based on bitwise XOR (`^`) and multiplication by 33. It produces a non-negative 32-bit integer,\n * which is then converted to a base-36 string (digits + lowercase letters) to produce a compact output.\n *\n * Useful for:\n * - Generating stable class names in CSS-in-JS libraries.\n * - Producing consistent cache keys.\n * - Quick and lightweight hashing needs where cryptographic security is not required.\n *\n * ⚠️ This is not cryptographically secure and should not be used for hashing passwords or sensitive data.\n *\n * @param input - The input string to hash.\n *\n * @returns A short, base-36 encoded hash string.\n *\n * @example\n * ```ts\n * const className = hashString('background-color: red;');\n * // → 'e4k1z0x'\n * ```\n */\nexport const hashString = (input: string): string => {\n let hash = 5381;\n\n for (let i = 0; i < input.length; i++) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n\n return (hash >>> 0).toString(36);\n};\n","export type DefinedProps<T extends object> = {\n [K in keyof T as T[K] extends undefined ? never : K]: Exclude<T[K], undefined>;\n};\n\n/**\n * Create a new object by removing properties whose values are `undefined`.\n *\n * Example:\n * ```ts\n * definedProps({ a: 1, b: undefined, c: 'x' });\n * // -> { a: number; c: string }\n * ```\n *\n * @template T - Input object shape.\n *\n * @param obj - The source object to clean.\n *\n * @returns A new object containing only keys whose runtime values are not `undefined`.\n */\nexport const definedProps = <T extends object>(obj: T): DefinedProps<T> =>\n Object.entries(obj).reduce((result, [key, value]) => {\n if (value !== undefined) {\n result[key] = value;\n }\n\n return result;\n }, {} as any);\n","/**\n * Converts a string to kebab-case format.\n *\n * This function transforms camelCase or PascalCase strings into kebab-case by inserting\n * hyphens between lowercase and uppercase letters, then converting everything to lowercase.\n *\n * @param input - The string to convert to kebab-case.\n *\n * @returns The kebab-case formatted string.\n *\n * @example\n * ```ts\n * toKebabCase('helloWorld'); // → 'hello-world'\n * toKebabCase('HelloWorld'); // → 'hello-world'\n * toKebabCase('hello123World'); // → 'hello123-world'\n * ```\n */\nexport const toKebabCase = (input: string): string =>\n input.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n","/**\n * Converts a camelCase string to dash-case format.\n *\n * This function transforms camelCase strings into dash-case by inserting\n * hyphens before uppercase letters and converting them to lowercase.\n * The function ensures that no hyphen is added at the start of the output string,\n * even if the input begins with an uppercase letter.\n *\n * @param input - The camelCase string to convert to dash-case.\n *\n * @returns The dash-case formatted string.\n *\n * @example\n * ```ts\n * camelToDashCase('helloWorld'); // → 'hello-world'\n * camelToDashCase('HelloWorld'); // → 'hello-world'\n * camelToDashCase('backgroundColor'); // → 'background-color'\n * ```\n */\nexport const camelToDashCase = (input: string): string => {\n // First handle the first character separately to avoid adding a hyphen at the start\n const firstChar = input.charAt(0);\n const restOfString = input.slice(1);\n\n // Convert the first character to the lowercase without adding a hyphen\n const firstCharProcessed = firstChar.toLowerCase();\n\n // Process the rest of the string normally, adding hyphens before uppercase letters\n const restProcessed = restOfString.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);\n\n return firstCharProcessed + restProcessed;\n};\n","/**\n * Splits a camelCase or PascalCase string into separate words with spaces.\n *\n * This function inserts spaces between lowercase and uppercase letters,\n * making camelCase or PascalCase strings more human-readable without\n * altering their original capitalization.\n *\n * @param input - The camelCase or PascalCase string to split into words.\n *\n * @returns The string with spaces inserted between words.\n *\n * @example\n * ```ts\n * camelToWords('helloWorld'); // → 'hello World'\n * camelToWords('HelloWorld'); // → 'Hello World'\n * camelToWords('userIDNumber'); // → 'user ID Number'\n * ```\n */\nexport const camelToWords = (input: string) => input.replace(/([a-z0-9])([A-Z])/g, '$1 $2');\n","/**\n * Splits a string into an array of filtered from redundant spaces words.\n *\n * @param input - The input string to be split.\n *\n * @returns An array of words from the input string.\n */\nexport const splitStringIntoWords = (input: string): string[] => {\n if (input.length === 0) {\n return [];\n }\n\n return input.split(' ').filter(Boolean);\n};\n","import { isNil } from '~/guards';\n\n/**\n * Checks whether the provided value is considered \"empty\".\n *\n * A value is considered empty if it is:\n * - `null`\n * - `undefined`\n * - `''`\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is empty; otherwise, `false`.\n */\nexport const isNilOrEmptyString = (value: unknown): value is null | undefined =>\n value === '' || isNil(value);\n","/**\n * Splits a file name into its base name and extension.\n *\n * Special cases:\n * - Files without a dot return `[fileName, \"\"]`\n * - Hidden files like `.gitignore` return `[\".gitignore\", \"\"]`\n * - Names ending with a trailing dot (e.g., `\"file.\"`) return `[\"file.\", \"\"]`\n * - Multi-dot names (e.g., `\"archive.tar.gz\"`) split on the last dot\n *\n * @param fileName - The full file name to parse.\n *\n * @returns A tuple where:\n * - index 0 is the base name\n * - index 1 is the file extension (lowercased), or an empty string if none exists\n */\nexport const parseFileName = (fileName: string) => {\n const lastDotIndex = fileName.lastIndexOf('.');\n\n // No dot or leading dot with no extension (e.g., \".gitignore\")\n if (lastDotIndex <= 0 || lastDotIndex === fileName.length - 1) {\n return [fileName, ''];\n }\n\n return [fileName.slice(0, lastDotIndex), fileName.slice(lastDotIndex + 1).toLowerCase()];\n};\n","/**\n * Finds all zero-based indices where a given single character occurs in a string.\n *\n * The string is scanned once from start to end and each matching character position is collected.\n *\n * ⚠️ Character comparison is performed at the UTF-16 code unit level\n * (`String.charCodeAt`), not by Unicode grapheme clusters.\n *\n * @param input - The string to scan.\n * @param targetChar - A single character to search for.\n *\n * @returns An array of zero-based indices for each occurrence of `targetChar`.\n * Returns an empty array if no matches are found.\n */\nexport const findCharIndices = (input: string, targetChar: string): number[] => {\n if (input.length === 0) {\n return [];\n }\n\n const targetCode = targetChar.charCodeAt(0);\n const indices: number[] = [];\n\n for (let i = 0; i < input.length; i++) {\n if (input.charCodeAt(i) === targetCode) {\n indices.push(i);\n }\n }\n\n return indices;\n};\n","import type { Nullable } from '~/types';\n\n/**\n * Context information for the currently processed character during string iteration.\n *\n * Provides the character index and access to adjacent characters in the input string.\n * All character values are UTF-16 code units.\n */\ninterface CharContext {\n /**\n * Zero-based index of the current character within the input string.\n */\n charIndex: number;\n /**\n * The previous character in the string, or `null` if the current character is the first one.\n */\n prevChar: Nullable<string>;\n /**\n * The next character in the string, or `null` if the current character is the last one.\n */\n nextChar: Nullable<string>;\n}\n\n/**\n * Callback invoked for each processed character during string iteration.\n */\ntype CharHandler = (char: string, context: CharContext) => void;\n\n/**\n * Predicate used to conditionally skip characters during string iteration.\n *\n * Returning `true` indicates that the current character should be skipped.\n */\ntype CharPredicate = (char: string, context: CharContext) => boolean;\n\n/**\n * Iterates over each character of a string and invokes a callback for each one.\n *\n * Iteration is performed over UTF-16 code units (not Unicode grapheme clusters).\n * Characters may be conditionally skipped using an optional predicate.\n *\n * @param input - The string to iterate over.\n * @param onChar - Invoked for each character that is not skipped.\n * @param shouldSkipChar - Optional predicate; returning `true` skips the character.\n */\nexport const forEachChar = (\n input: string,\n onChar: CharHandler,\n shouldSkipChar?: CharPredicate,\n): void => {\n if (input.length === 0) {\n return;\n }\n\n const length = input.length;\n\n for (let charIndex = 0; charIndex < length; charIndex++) {\n const char = input[charIndex];\n\n const context: CharContext = {\n charIndex,\n prevChar: charIndex > 0 ? input[charIndex - 1] : null,\n nextChar: charIndex < length - 1 ? input[charIndex + 1] : null,\n };\n\n if (shouldSkipChar?.(char, context)) {\n continue;\n }\n\n onChar(char, context);\n }\n};\n","import { splitStringIntoWords } from './split-string-into-words';\n\n/**\n * Returns the uppercase initials of the words in a string.\n *\n * The first character of each word is extracted, concatenated, and uppercased.\n *\n * @param input - The input string.\n * @param maxWords - Maximum number of words to include when generating initials.\n * Defaults to `Infinity`.\n *\n * @returns A string containing the uppercase initials of the selected words.\n */\nexport const getWordsInitials = (input: string, maxWords = Infinity): string => {\n if (input.length === 0) {\n return '';\n }\n\n return splitStringIntoWords(input)\n .slice(0, maxWords)\n .map(word => word[0])\n .join('')\n .toUpperCase();\n};\n","/**\n * Splits a string into parts, transforms each part, then joins them back together.\n *\n * Common use cases:\n *\n * - Transforming selector groups:\n *\n * ```ts\n * splitMapJoin(\".a, .b\", \",\", part => `.scope ${part}`);\n * // \".scope .a, .scope .b\"\n * ```\n *\n * - Normalizing spacing:\n *\n * ```ts\n * splitMapJoin(\"a , b ,c\", \",\", part => part);\n * // \"a,b,c\"\n * ```\n *\n * - Custom join formatting:\n *\n * ```ts\n * splitMapJoin(\"a,b,c\", \",\", part => part.toUpperCase(), \".\");\n * // \"A.B.C\"\n * ```\n *\n * @param input - The raw input string to process.\n * @param separator - The delimiter used to split the input (e.g. `\",\"`, `\" \"`).\n * @param mapFn - Function applied to each trimmed part.\n * @param joinWith - Optional join separator (defaults to the same value as `separator`).\n *\n * @returns The transformed and re-joined string.\n */\nexport const splitMapJoin = (\n input: string,\n separator: string,\n mapFn: (part: string, index: number) => string,\n joinWith: string = separator,\n): string =>\n input\n .split(separator)\n .map((part, index) => mapFn(part.trim(), index))\n .join(joinWith);\n","import type { KeysWithArrayValues, KeysWithNonArrayValues } from '~/types';\nimport type { HoneyTreeFlatNode } from '~/tree';\n\n/**\n * Flattens a hierarchical tree into a single preorder array.\n *\n * Each node in the returned list is stripped of its nested children property\n * (`childrenKey`) and enriched with hierarchy metadata:\n *\n * - `parentId` — identifier of the parent node (`undefined` for roots)\n * - `depthLevel` — nesting depth starting at `0`\n * - `childCount` — number of direct child nodes\n *\n * The flattening order is **preorder**, meaning parents always appear before\n * their descendants. This representation is especially useful for rendering\n * tree-based UIs such as TreeSelect components, nested menus, and folder pickers.\n *\n * @template OriginItem - Original node shape of the hierarchical structure.\n *\n * @param items - Root-level nodes to flatten. If undefined, an empty array is returned.\n * @param nodeIdKey - Key that uniquely identifies each node.\n * @param childrenKey - Key containing the nested child node array.\n *\n * @param flatTree - Internal accumulator used during recursion.\n * @param parentId - Parent identifier for the current recursion level.\n * @param depthLevel - Current depth level, where `0` represents the root.\n *\n * @returns A flat preorder list of tree nodes with hierarchy metadata attached,\n * excluding the original children property.\n *\n * @example\n * ```ts\n * const tree = [\n * {\n * id: 1,\n * name: 'Root',\n * children: [{ id: 2, name: 'Child', children: [] }],\n * },\n * ];\n *\n * const flatTree = flattenTree(tree, 'id', 'children');\n *\n * // [\n * // { id: 1, name: 'Root', parentId: undefined, depthLevel: 0, childCount: 1 },\n * // { id: 2, name: 'Child', parentId: 1, depthLevel: 1, childCount: 0 }\n * // ]\n * ```\n */\nexport const flattenTree = <OriginItem extends object>(\n items: OriginItem[] | undefined,\n nodeIdKey: KeysWithNonArrayValues<OriginItem>,\n childrenKey: KeysWithArrayValues<OriginItem>,\n ///\n flatTree: HoneyTreeFlatNode<OriginItem, typeof childrenKey>[] = [],\n parentId: OriginItem[KeysWithNonArrayValues<OriginItem>] | undefined = undefined,\n depthLevel = 0,\n): HoneyTreeFlatNode<OriginItem, typeof childrenKey>[] => {\n items?.forEach(item => {\n const { [childrenKey]: _, ...nodeData } = item;\n\n const children = item[childrenKey];\n const hasChildrenArray = Array.isArray(children);\n\n flatTree.push({\n ...nodeData,\n parentId,\n depthLevel,\n childCount: hasChildrenArray ? children.length : 0,\n });\n\n if (hasChildrenArray) {\n const parentId = item[nodeIdKey];\n\n flattenTree(children, nodeIdKey, childrenKey, flatTree, parentId, depthLevel + 1);\n }\n });\n\n return flatTree;\n};\n","import type { KeysWithNonArrayValues } from '~/types';\nimport type { HoneyTreeFlatNode } from '~/tree';\n\n/**\n * Returns the direct children of a given parent node from a flattened tree.\n *\n * This helper filters a flat tree representation (`HoneyTreeFlatNode`) and\n * selects only nodes whose `parentId` matches the provided identifier.\n *\n * ⚠️ Only direct children are returned - descendants at deeper levels are not included.\n *\n * An optional predicate may be provided to further narrow the result set\n * (e.g. filtering by depth, type, or custom node flags).\n *\n * @template OriginItem - Original node shape of the hierarchical structure.\n * @template ChildrenKey - Key of the removed nested children property.\n *\n * @param flatTree - Flat preorder list of tree nodes containing hierarchy metadata.\n * @param parentId - Identifier of the parent node whose direct children should be returned.\n * @param predicate - Optional additional filter applied to each matched child node.\n *\n * @returns An array of nodes that are direct children of the specified parent.\n *\n * @example\n * ```ts\n * const children = getTreeChildren(flatTree, 1);\n *\n * // Returns all nodes where parentId === 1\n * ```\n *\n * @example\n * ```ts\n * const shallowChildren = getTreeChildren(\n * flatTree,\n * 1,\n * node => node.depthLevel <= 2,\n * );\n *\n * // Returns only children of node 1 that satisfy the predicate.\n * ```\n */\nexport const getTreeChildren = <OriginItem extends object, ChildrenKey extends string>(\n flatTree: HoneyTreeFlatNode<OriginItem, ChildrenKey>[],\n parentId: OriginItem[KeysWithNonArrayValues<OriginItem>],\n predicate?: (node: HoneyTreeFlatNode<OriginItem, ChildrenKey>) => boolean,\n) => flatTree.filter(node => node.parentId === parentId && (!predicate || predicate(node)));\n","import type { KeysWithNonArrayValues, KeysWithStringValues } from '~/types';\nimport type { HoneyTreeFlatNode } from '~/tree';\nimport { assert, isNull, isUndefined } from '~/guards';\nimport { splitStringIntoWords } from '~/string';\n\n/**\n * Performs a context-aware search over a flattened tree.\n *\n * Matching is applied to the provided string field (`nodeValueKey`) using\n * **case-insensitive, word-prefix comparison**:\n *\n * - The query is split into words\n * - Each query word must match the start of at least one word in the node value\n *\n * Unlike a simple filter, this function preserves hierarchical context:\n *\n * - When a nested node matches, all of its ancestor nodes are included, so the\n * result remains navigable.\n * - When a root node matches, its full descendant subtree is included so the\n * hierarchy stays intact.\n *\n * This makes the utility ideal for searchable tree-based UIs such as\n * TreeSelect components, folder pickers, nested menus, and grouped lists.\n *\n * @template OriginItem - Original node shape of the hierarchical structure.\n * @template ChildrenKey - Key of the removed nested children property.\n *\n * @param flatTree - Flat preorder list of tree nodes containing hierarchy metadata.\n * @param nodeIdKey - Key that uniquely identifies each node.\n * @param nodeValueKey - Key containing the searchable string value (e.g. `\"name\"`).\n * @param searchQuery - User input query. Split into words and matched by prefix.\n *\n * @returns A filtered flat list containing:\n * - all matching nodes\n * - their ancestor chain (for nested matches)\n * - full descendant subtrees (for root-level matches)\n *\n * @example\n * ```ts\n * const results = searchTree(flatTree, 'id', 'label', 'kit che');\n *\n * // Matches nodes where words start with \"kit\" and \"che\"\n * // (e.g. \"Kitchen Chair\"), including their parents.\n * ```\n *\n * @example\n * ```ts\n * // If a deep child matches, ancestors are included:\n * //\n * // Root\n * // └─ Category\n * // └─ Item ← matches\n * //\n * // Result includes: Root, Category, Item\n * ```\n */\nexport const searchTree = <OriginItem extends object, ChildrenKey extends string>(\n flatTree: HoneyTreeFlatNode<OriginItem, ChildrenKey>[],\n nodeIdKey: KeysWithNonArrayValues<OriginItem>,\n nodeValueKey: KeysWithStringValues<OriginItem>,\n searchQuery: string,\n) => {\n const searchWords = splitStringIntoWords(searchQuery.toLowerCase());\n if (!searchWords.length) {\n return flatTree;\n }\n\n const nodeIdToIndexMap = flatTree.reduce<Record<string, number>>((result, node, nodeIndex) => {\n // Map node id → index for fast ancestor lookup.\n result[node[nodeIdKey as never]] = nodeIndex;\n\n return result;\n }, {});\n\n return flatTree.reduce<HoneyTreeFlatNode<OriginItem, ChildrenKey>[]>((matchedNodes, node) => {\n const nodeValue = node[nodeValueKey as never];\n // If the item value is null, undefined or empty string\n if (!nodeValue) {\n return matchedNodes;\n }\n\n if (\n matchedNodes.some(matchedNode => matchedNode[nodeIdKey as never] === node[nodeIdKey as never])\n ) {\n return matchedNodes;\n }\n\n const nodeValueWords = splitStringIntoWords((nodeValue as string).toLowerCase());\n\n const isNodeMatched = searchWords.every(searchWord =>\n nodeValueWords.some(word => word.startsWith(searchWord)),\n );\n\n if (isNodeMatched) {\n if (isUndefined(node.parentId)) {\n matchedNodes.push(node);\n\n const insertNestedItems = (targetNode: HoneyTreeFlatNode<OriginItem, ChildrenKey>) => {\n if (!targetNode.childCount) {\n return;\n }\n\n flatTree.forEach(node => {\n if (node.parentId === targetNode[nodeIdKey as never]) {\n matchedNodes.push(node);\n\n insertNestedItems(node);\n }\n });\n };\n\n insertNestedItems(node);\n } else {\n const insertParentNodes = (targetNode: HoneyTreeFlatNode<OriginItem, ChildrenKey>) => {\n const parentNodeIndex = nodeIdToIndexMap[targetNode.parentId as never];\n const parentNode = flatTree[parentNodeIndex];\n\n if (!isUndefined(parentNode.parentId)) {\n insertParentNodes(parentNode);\n }\n\n const prevNodeParentId = matchedNodes.length\n ? matchedNodes[matchedNodes.length - 1].parentId\n : null;\n\n const shouldInsertParentNode =\n isNull(prevNodeParentId) || prevNodeParentId !== targetNode.parentId;\n\n if (shouldInsertParentNode) {\n assert(parentNode, '[@react-hive/honey-utils]: Parent node was not found.');\n\n matchedNodes.push(parentNode);\n }\n };\n\n insertParentNodes(node);\n\n matchedNodes.push(node);\n }\n }\n\n return matchedNodes;\n }, []);\n};\n"],"names":["cloneBlob","blob","Blob","type","getElementOffsetRect","element","DOMRect","offsetLeft","offsetTop","clientWidth","clientHeight","isAnchorHtmlElement","tagName","isContentEditableHtmlElement","getAttribute","FOCUSABLE_HTML_TAGS","isHtmlElementFocusable","style","window","getComputedStyle","visibility","display","disabled","tabIndex","includes","href","getFocusableHtmlElements","container","Array","from","querySelectorAll","filter","moveFocusWithinContainer","direction","wrap","getNextIndex","activeElement","document","scope","parentElement","focusableElements","length","currentIndex","indexOf","nextIndex","focus","assert","condition","message","Error","isNull","value","isNil","isDefined","isUndefined","undefined","isNumber","isBool","isObject","isEmptyObject","Object","keys","isDate","Date","isBlob","isError","isValidDate","isNaN","getTime","isRegExp","RegExp","isMap","Map","isSet","Set","isSymbol","isFiniteNumber","isFinite","isInteger","Number","isDecimal","isArray","isEmptyArray","compact","array","Boolean","unique","chunk","size","Math","ceil","_","index","slice","intersection","arrays","first","rest","item","every","difference","exclude","pipe","fns","arg","reduce","prev","fn","compose","reduceRight","noop","isFunction","not","args","once","result","called","apply","this","isPromise","then","runSequential","async","results","i","push","runParallel","Promise","all","map","filterSequential","predicate","filterParallel","someAsync","everyAsync","reduceAsync","initialValue","accumulator","findAsync","delay","delayMs","resolve","setTimeout","timeout","promise","timeoutMs","errorMessage","race","reject","retry","task","maxAttempts","backoff","onRetry","lastError","attempt","e","delayTime","isString","downloadFile","file","fileName","target","link","createElement","objectUrl","URL","createObjectURL","download","body","appendChild","click","remove","revokeObjectURL","hasXOverflow","scrollWidth","getXOverflowWidth","max","hasYOverflow","scrollHeight","getYOverflowHeight","calculateCenterOffset","overflowSize","containerSize","elementOffset","elementSize","targetOffset","min","centerElementInContainer","containerElement","elementToCenter","axis","translateX","translateY","transform","parse2DMatrix","matrixMatch","getPropertyValue","match","scaleX","scaleY","skewX","skewY","split","parseFloat","isLocalStorageReadable","localStorage","getItem","getLocalStorageCapabilities","readable","writable","key","setItem","removeItem","isFile","File","fileListToFiles","fileList","files","blobToFile","traverseFileSystemDirectory","directoryEntry","skipFiles","skipFilesSet","entries","directoryReader","createReader","readAll","readEntries","restEntries","readFileSystemDirectoryEntries","entry","isDirectory","has","name","flat","readFilesFromDataTransfer","dataTransfer","traverseOptions","items","tasks","itemIndex","webkitGetAsEntry","getAsFile","invokeIfFunction","input","resolveBoundedDelta","delta","candidate","applyInertiaStep","velocityPxMs","deltaTimeMs","friction","minVelocityPxMs","emaAlpha","abs","nextValue","pureVelocityPxMs","exp","nextVelocityPxMs","generateEphemeralId","floor","performance","now","toString","random","getDOMRectIntersectionRatio","sourceRect","targetRect","right","left","bottom","top","width","height","resolveAxisDelta","allowFallback","invert","sign","deltaX","deltaY","calculateEuclideanDistance","startX","startY","endX","endY","hypot","calculateMovingSpeed","distance","elapsedTime","calculatePercentage","percentage","hashString","hash","charCodeAt","definedProps","obj","toKebabCase","replace","toLowerCase","camelToDashCase","firstChar","charAt","restOfString","letter","camelToWords","splitStringIntoWords","isNilOrEmptyString","parseFileName","lastDotIndex","lastIndexOf","findCharIndices","targetChar","targetCode","indices","forEachChar","onChar","shouldSkipChar","charIndex","char","context","prevChar","nextChar","getWordsInitials","maxWords","Infinity","word","join","toUpperCase","splitMapJoin","separator","mapFn","joinWith","part","trim","flattenTree","nodeIdKey","childrenKey","flatTree","parentId","depthLevel","forEach","nodeData","children","hasChildrenArray","childCount","getTreeChildren","node","searchTree","nodeValueKey","searchQuery","searchWords","nodeIdToIndexMap","nodeIndex","matchedNodes","nodeValue","some","matchedNode","nodeValueWords","searchWord","startsWith","insertNestedItems","targetNode","insertParentNodes","parentNodeIndex","parentNode","prevNodeParentId"],"ignoreList":[],"sourceRoot":""}
1
+ {"version":3,"file":"index.mjs","mappings":"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","sources":["webpack://@react-hive/honey-utils/./src/dom/dom.ts","webpack://@react-hive/honey-utils/./src/a11y/focus/is-html-element-focusable.ts","webpack://@react-hive/honey-utils/./src/a11y/focus/get-focusable-html-elements.ts","webpack://@react-hive/honey-utils/./src/a11y/focus/move-focus-within-container.ts","webpack://@react-hive/honey-utils/./src/guards.ts","webpack://@react-hive/honey-utils/./src/array.ts","webpack://@react-hive/honey-utils/./src/function/function.ts","webpack://@react-hive/honey-utils/./src/async/async.ts","webpack://@react-hive/honey-utils/./src/async/delay.ts","webpack://@react-hive/honey-utils/./src/async/timeout.ts","webpack://@react-hive/honey-utils/./src/async/retry.ts","webpack://@react-hive/honey-utils/./src/string/is-string.ts","webpack://@react-hive/honey-utils/./src/dom/file/download-file.ts","webpack://@react-hive/honey-utils/./src/dom/layout/overflow.ts","webpack://@react-hive/honey-utils/./src/geometry/layout/calculate-center-offset.ts","webpack://@react-hive/honey-utils/./src/dom/layout/center-element-in-container.ts","webpack://@react-hive/honey-utils/./src/dom/transform/parse-2d-matrix.ts","webpack://@react-hive/honey-utils/./src/env/storage/local-storage.ts","webpack://@react-hive/honey-utils/./src/file.ts","webpack://@react-hive/honey-utils/./src/function/invoke-if-function.ts","webpack://@react-hive/honey-utils/./src/geometry/resolve-bounded-delta.ts","webpack://@react-hive/honey-utils/./src/geometry/apply-inertia-step.ts","webpack://@react-hive/honey-utils/./src/id/generate-ephemeral-id.ts","webpack://@react-hive/honey-utils/./src/intersection/get-dom-rect-intersection-ratio.ts","webpack://@react-hive/honey-utils/./src/intersection/resolve-axis-delta.ts","webpack://@react-hive/honey-utils/./src/math/math.ts","webpack://@react-hive/honey-utils/./src/math/hash-string.ts","webpack://@react-hive/honey-utils/./src/object.ts","webpack://@react-hive/honey-utils/./src/string/to-kebab-case.ts","webpack://@react-hive/honey-utils/./src/string/camel-to-dash-case.ts","webpack://@react-hive/honey-utils/./src/string/camel-to-words.ts","webpack://@react-hive/honey-utils/./src/string/split-string-into-words.ts","webpack://@react-hive/honey-utils/./src/string/is-nil-or-empty-string.ts","webpack://@react-hive/honey-utils/./src/string/parse-file-name.ts","webpack://@react-hive/honey-utils/./src/string/find-char-indices.ts","webpack://@react-hive/honey-utils/./src/string/for-each-char.ts","webpack://@react-hive/honey-utils/./src/string/get-words-initials.ts","webpack://@react-hive/honey-utils/./src/string/split-map-join.ts","webpack://@react-hive/honey-utils/./src/tree/flatten-tree.ts","webpack://@react-hive/honey-utils/./src/tree/get-tree-children.ts","webpack://@react-hive/honey-utils/./src/tree/search-tree.ts","webpack://@react-hive/honey-utils/./src/color/hex-with-alpha.ts"],"sourcesContent":["/**\n * Creates a clone of a Blob object.\n *\n * @param blob - The Blob object to clone.\n *\n * @returns A new Blob with the same content and type as the original.\n */\nexport const cloneBlob = (blob: Blob): Blob => new Blob([blob], { type: blob.type });\n\n/**\n * Returns the bounding DOMRect of an element based on offset and client dimensions.\n *\n * This utility is useful when you need a stable, layout-based rect\n * without triggering a reflow via `getBoundingClientRect()`.\n *\n * @param element - The target HTML element.\n * @returns A `DOMRect` representing the element’s offset position and size.\n */\nexport const getElementOffsetRect = (element: HTMLElement): DOMRect =>\n new DOMRect(element.offsetLeft, element.offsetTop, element.clientWidth, element.clientHeight);\n\n/**\n * Determines whether the given HTMLElement is an HTMLAnchorElement.\n *\n * Acts as a type guard so that TypeScript narrows `element` to\n * `HTMLAnchorElement` when the function returns `true`.\n *\n * An element qualifies as an anchor by having a tag name of `\"A\"`.\n *\n * @param element - The element to test.\n *\n * @returns Whether the element is an anchor element.\n */\nexport const isAnchorHtmlElement = (element: HTMLElement): element is HTMLAnchorElement =>\n element.tagName === 'A';\n\n/**\n * Checks whether an element is explicitly marked as contenteditable.\n *\n * Browsers treat elements with `contenteditable=\"true\"` as focusable,\n * even if they are not normally keyboard-focusable.\n *\n * @param element - The element to inspect.\n *\n * @returns True if `contenteditable=\"true\"` is set.\n */\nexport const isContentEditableHtmlElement = (element: HTMLElement) =>\n element.getAttribute('contenteditable') === 'true';\n","import type { Nullable } from '~/types';\nimport { isAnchorHtmlElement, isContentEditableHtmlElement } from '~/dom';\n\nexport const FOCUSABLE_HTML_TAGS = ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON', 'A'];\n\n/**\n * Determines whether an HTMLElement is focusable under standard browser rules.\n *\n * The function checks a combination of factors:\n * - The element must be rendered (not `display: none` or `visibility: hidden`).\n * - Disabled form controls are never focusable.\n * - Elements with `tabindex=\"-1\"` are intentionally removed from the focus order.\n * - Certain native HTML elements are inherently focusable (e.g. inputs, buttons, anchors with `href`).\n * - Elements with `contenteditable=\"true\"` are treated as focusable.\n * - Any element with a valid `tabindex` (not null) is considered focusable.\n *\n * This logic approximates how browsers and the accessibility tree\n * determine real-world focusability—not just tabindex presence.\n *\n * @param element - The element to test. `null` or `undefined` will return `false`.\n *\n * @returns Whether the element is focusable.\n */\nexport const isHtmlElementFocusable = (element: Nullable<HTMLElement>): boolean => {\n if (!element) {\n return false;\n }\n\n const style = window.getComputedStyle(element);\n if (style.visibility === 'hidden' || style.display === 'none') {\n return false;\n }\n\n if ('disabled' in element && element.disabled) {\n return false;\n }\n\n // Explicitly removed from tab order\n const tabIndex = element.getAttribute('tabindex');\n if (tabIndex === '-1') {\n return false;\n }\n\n if (FOCUSABLE_HTML_TAGS.includes(element.tagName)) {\n if (isAnchorHtmlElement(element)) {\n return element.href !== '';\n }\n\n return true;\n }\n\n if (isContentEditableHtmlElement(element)) {\n return true;\n }\n\n return tabIndex !== null;\n};\n","import { isHtmlElementFocusable } from '~/a11y';\n\n/**\n * Collects all focusable descendant elements within a container.\n *\n * The function queries *all* elements under the container and filters them\n * using `isHtmlElementFocusable`, producing a reliable list of elements\n * that can receive keyboard focus in real-world browser conditions.\n *\n * @param container - The root container whose focusable children will be found.\n *\n * @returns An array of focusable HTMLElements in DOM order.\n */\nexport const getFocusableHtmlElements = (container: HTMLElement): HTMLElement[] =>\n Array.from(container.querySelectorAll<HTMLElement>('*')).filter(isHtmlElementFocusable);\n","import type { Nullable } from '~/types';\nimport { getFocusableHtmlElements } from '~/a11y';\n\nexport type FocusMoveDirection = 'next' | 'previous';\n\nexport interface MoveFocusWithinContainerOptions {\n /**\n * Whether focus navigation should wrap around when reaching\n * the beginning or end of the focusable elements list.\n *\n * When enabled, moving past the last element focuses the first,\n * and moving before the first focuses the last.\n *\n * @default true\n */\n wrap?: boolean;\n /**\n * Custom resolver for determining the next focus index.\n *\n * When provided, this function overrides the default navigation logic\n * and receives full control over how the focus moves.\n *\n * @param currentIndex - Index of the currently focused element.\n * @param direction - Direction in which focus is moving.\n * @param elements - Ordered list of focusable elements within the container.\n *\n * @returns The index of the element to focus next, or `null` to prevent focus movement.\n */\n getNextIndex?: (\n currentIndex: number,\n direction: FocusMoveDirection,\n elements: HTMLElement[],\n ) => Nullable<number>;\n}\n\n/**\n * Moves focus to the next or previous focusable element within a container.\n *\n * This utility is commonly used to implement accessible keyboard navigation patterns such as:\n * - roving tabindex\n * - custom dropdowns\n * - tablists\n * - menus\n * - horizontal or vertical navigation groups\n *\n * Focus movement is scoped to a container and operates on the list of\n * focusable descendants returned by `getFocusableHtmlElements`.\n *\n * @param direction - Direction in which focus should move (`'next'` or `'previous'`).\n * @param container - Optional container that defines the focus scope.\n * If omitted, the parent element of the currently focused element is used.\n * @param options - Optional configuration controlling wrapping behavior and custom index resolution.\n *\n * @remarks\n * - This function reads from and mutates the document's focus state.\n * - If no active element exists, no container can be resolved,\n * or the active element is not part of the focusable set, no action is taken.\n * - When `getNextIndex` is provided, it fully overrides the default wrapping and directional logic.\n */\nexport const moveFocusWithinContainer = (\n direction: FocusMoveDirection,\n container: Nullable<HTMLElement> = null,\n { wrap = true, getNextIndex }: MoveFocusWithinContainerOptions = {},\n): void => {\n const activeElement = document.activeElement as Nullable<HTMLElement>;\n const scope = container ?? activeElement?.parentElement;\n\n if (!activeElement || !scope) {\n return;\n }\n\n const focusableElements = getFocusableHtmlElements(scope);\n if (focusableElements.length === 0) {\n return;\n }\n\n const currentIndex = focusableElements.indexOf(activeElement);\n if (currentIndex === -1) {\n return;\n }\n\n let nextIndex: Nullable<number>;\n\n if (getNextIndex) {\n nextIndex = getNextIndex(currentIndex, direction, focusableElements);\n } else {\n if (direction === 'next') {\n nextIndex = currentIndex + 1;\n\n if (nextIndex >= focusableElements.length) {\n nextIndex = wrap ? 0 : null;\n }\n } else {\n nextIndex = currentIndex - 1;\n\n if (nextIndex < 0) {\n nextIndex = wrap ? focusableElements.length - 1 : null;\n }\n }\n }\n\n if (nextIndex === null) {\n return;\n }\n\n focusableElements[nextIndex]?.focus();\n};\n","export function assert(condition: any, message: string): asserts condition {\n if (!condition) {\n throw new Error(message);\n }\n}\n\n/**\n * Checks if a value is null.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is null; otherwise, `false`.\n */\nexport const isNull = (value: unknown): value is null => value === null;\n\n/**\n * Checks if a value is null or undefined.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is `null` or `undefined`, otherwise `false`.\n */\nexport const isNil = (value: unknown): value is null | undefined =>\n value === undefined || value === null;\n\n/**\n * Checks if a value is neither `null` nor `undefined`.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is defined (not `null` or `undefined`); otherwise, `false`.\n */\nexport const isDefined = <T>(value: T): value is NonNullable<T> =>\n value !== null && value !== undefined;\n\n/**\n * Checks if a value is undefined.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is undefined; otherwise, `false`.\n */\nexport const isUndefined = (value: unknown): value is undefined => value === undefined;\n\n/**\n * Checks if a value is a number.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a number; otherwise, `false`.\n */\nexport const isNumber = (value: unknown): value is number => typeof value === 'number';\n\n/**\n * Checks if a value is a boolean.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a boolean; otherwise, `false`.\n */\nexport const isBool = (value: unknown): value is boolean => typeof value === 'boolean';\n\n/**\n * Checks if a value is an object.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an object; otherwise, `false`.\n */\nexport const isObject = (value: unknown): value is object => typeof value === 'object';\n\n/**\n * Checks if a value is an empty object (no own enumerable properties).\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an empty object; otherwise, `false`.\n */\nexport const isEmptyObject = (value: unknown): value is Record<string, never> =>\n isObject(value) && !isNull(value) && Object.keys(value).length === 0;\n\n/**\n * Checks if a value is a Date object.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Date object; otherwise, `false`.\n */\nexport const isDate = (value: unknown): value is Date => value instanceof Date;\n\n/**\n * Checks if a value is a `Blob`.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Blob object; otherwise, `false`.\n */\nexport const isBlob = (value: unknown): value is Blob => value instanceof Blob;\n\n/**\n * Checks if a value is an `Error` object.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an Error instance; otherwise, `false`.\n */\nexport const isError = (value: unknown): value is Error => value instanceof Error;\n\n/**\n * Checks if a value is a valid Date object (not Invalid Date).\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a valid Date object; otherwise, `false`.\n */\nexport const isValidDate = (value: unknown): value is Date =>\n isDate(value) && !isNaN(value.getTime());\n\n/**\n * Checks if a value is a RegExp object.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a RegExp object; otherwise, `false`.\n */\nexport const isRegExp = (value: unknown): value is RegExp => value instanceof RegExp;\n\n/**\n * Checks if a value is a Map.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Map; otherwise, `false`.\n */\nexport const isMap = (value: unknown): value is Map<unknown, unknown> => value instanceof Map;\n\n/**\n * Checks if a value is a Set.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Set; otherwise, `false`.\n */\nexport const isSet = (value: unknown): value is Set<unknown> => value instanceof Set;\n\n/**\n * Checks if a value is a Symbol.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Symbol; otherwise, `false`.\n */\nexport const isSymbol = (value: unknown): value is symbol => typeof value === 'symbol';\n\n/**\n * Checks if a value is a finite number.\n *\n * A finite number is a number that is not `NaN`, `Infinity`, or `-Infinity`.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a finite number; otherwise, `false`.\n *\n * @example\n * ```ts\n * isFiniteNumber(10); // true\n * isFiniteNumber(3.14); // true\n * isFiniteNumber(-5); // true\n * ```\n *\n * @example\n * ```ts\n * isFiniteNumber(NaN); // false\n * isFiniteNumber(Infinity); // false\n * isFiniteNumber(-Infinity); // false\n * ```\n *\n * @example\n * ```ts\n * isFiniteNumber('10'); // false\n * isFiniteNumber(null); // false\n * isFiniteNumber(undefined); // false\n * ```\n */\nexport const isFiniteNumber = (value: unknown): value is number =>\n isNumber(value) && isFinite(value);\n\n/**\n * Checks if a value is an integer.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an integer; otherwise, `false`.\n */\nexport const isInteger = (value: unknown): value is number =>\n isNumber(value) && Number.isInteger(value);\n\n/**\n * Checks if a value is a decimal number (finite and non-integer).\n *\n * A decimal number is a finite number that has a fractional part (i.e. not an integer).\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a decimal number; otherwise, `false`.\n *\n * @example\n * ```ts\n * isDecimal(1.5); // true\n * isDecimal(-0.25); // true\n * isDecimal(0.1); // true\n * ```\n *\n * @example\n * ```ts\n * isDecimal(1); // false\n * isDecimal(0); // false\n * isDecimal(-10); // false\n * ```\n *\n * @example\n * ```ts\n * isDecimal(NaN); // false\n * isDecimal(Infinity); // false\n * ```\n *\n * @example\n * ```ts\n * isDecimal('1.5'); // false\n * isDecimal(null); // false\n * isDecimal(undefined); // false\n * ```\n */\nexport const isDecimal = (value: unknown): value is number =>\n isFiniteNumber(value) && !Number.isInteger(value);\n","import { assert } from '~/guards';\n\n/**\n * Checks if a value is an array.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an array; otherwise, `false`.\n */\nexport const isArray = (value: unknown): value is unknown[] => Array.isArray(value);\n\n/**\n * Checks if a value is an empty array.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is an empty array; otherwise, `false`.\n */\nexport const isEmptyArray = (value: unknown): value is [] => isArray(value) && value.length === 0;\n\n/**\n * Represents all falsy values.\n */\ntype Falsy = false | null | undefined | 0 | '';\n\n/**\n * Removes all falsy values from an array.\n *\n * Falsy values include: `false`, `0`, `''` (empty string), `null`, `undefined`, and `NaN`.\n *\n * Useful for cleaning up arrays with optional, nullable, or conditionally included items.\n *\n * @template T - The type of the truthy items.\n *\n * @param array - An array possibly containing falsy values.\n *\n * @returns A new array containing only truthy values of type `T`.\n *\n * @example\n * ```ts\n * compact([0, 1, false, 2, '', 3, null, undefined, NaN]); // [1, 2, 3]\n * ```\n */\nexport const compact = <T>(array: (T | Falsy)[]): T[] => array.filter(Boolean) as T[];\n\n/**\n * Returns a new array with duplicate values removed.\n *\n * Uses Set for efficient duplicate removal while preserving the original order.\n *\n * @template T - The type of the items in the array.\n *\n * @param array - The input array that may contain duplicate values.\n *\n * @returns A new array with only unique values, maintaining the original order.\n *\n * @example\n * ```ts\n * unique([1, 2, 2, 3, 1, 4]); // [1, 2, 3, 4]\n * unique(['a', 'b', 'a', 'c']); // ['a', 'b', 'c']\n * ```\n */\nexport const unique = <T>(array: T[]): T[] => [...new Set(array)];\n\n/**\n * Splits an array into chunks of the specified size.\n *\n * Useful for pagination, batch processing, or creating grid layouts.\n *\n * @template T - The type of the items in the array.\n *\n * @param array - The input array to be chunked.\n * @param size - The size of each chunk. Must be greater than 0.\n *\n * @returns An array of chunks, where each chunk is an array of the specified size\n * (except possibly the last chunk, which may be smaller).\n *\n * @example\n * ```ts\n * chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]\n * chunk(['a', 'b', 'c', 'd'], 3); // [['a', 'b', 'c'], ['d']]\n * ```\n */\nexport const chunk = <T>(array: T[], size: number): T[][] => {\n assert(size > 0, 'Chunk size must be greater than 0');\n\n return Array.from({ length: Math.ceil(array.length / size) }, (_, index) =>\n array.slice(index * size, (index + 1) * size),\n );\n};\n\n/**\n * Returns an array containing elements that exist in all provided arrays.\n *\n * @template T - The type of the items in the arrays.\n *\n * @param arrays - Two or more arrays to find common elements from.\n *\n * @returns A new array containing only the elements that exist in all input arrays.\n *\n * @example\n * ```ts\n * intersection([1, 2, 3], [2, 3, 4]); // [2, 3]\n * intersection(['a', 'b', 'c'], ['b', 'c', 'd'], ['b', 'e']); // ['b']\n * ```\n */\nexport const intersection = <T>(...arrays: T[][]): T[] => {\n if (arrays.length === 0) {\n return [];\n }\n\n if (arrays.length === 1) {\n return [...arrays[0]];\n }\n\n const [first, ...rest] = arrays;\n const uniqueFirst = unique(first);\n\n return uniqueFirst.filter(item => rest.every(array => array.includes(item)));\n};\n\n/**\n * Returns elements from the first array that don't exist in the second array.\n *\n * @template T - The type of the items in the arrays.\n *\n * @param array - The source array.\n * @param exclude - The array containing elements to exclude.\n *\n * @returns A new array with elements from the first array that don't exist in the second array.\n *\n * @example\n * ```ts\n * difference([1, 2, 3, 4], [2, 4]); // [1, 3]\n * difference(['a', 'b', 'c'], ['b']); // ['a', 'c']\n * ```\n */\nexport const difference = <T>(array: T[], exclude: T[]): T[] =>\n array.filter(item => !exclude.includes(item));\n\ntype PipeFn = (arg: unknown) => unknown;\n\ntype Pipe = {\n <A, B>(fn1: (a: A) => B): (a: A) => B;\n <A, B, C>(fn1: (a: A) => B, fn2: (b: B) => C): (a: A) => C;\n <A, B, C, D>(fn1: (a: A) => B, fn2: (b: B) => C, fn3: (c: C) => D): (a: A) => D;\n <A, B, C, D, E>(\n fn1: (a: A) => B,\n fn2: (b: B) => C,\n fn3: (c: C) => D,\n fn4: (d: D) => E,\n ): (a: A) => E;\n <A, B, C, D, E, F>(\n fn1: (a: A) => B,\n fn2: (b: B) => C,\n fn3: (c: C) => D,\n fn4: (d: D) => E,\n fn5: (e: E) => F,\n ): (a: A) => F;\n (...fns: PipeFn[]): (arg: unknown) => unknown;\n};\n\n/**\n * Composes multiple unary functions into a single function, applying them from left to right.\n *\n * Useful for building a data processing pipeline where the output of one function becomes the input of the next.\n *\n * Types are inferred up to 5 chained functions for full type safety. Beyond that, it falls back to the unknown.\n *\n * @param fns - A list of unary functions to compose.\n *\n * @returns A new function that applies all functions from left to right.\n *\n * @example\n * ```ts\n * const add = (x: number) => x + 1;\n * const double = (x: number) => x * 2;\n * const toStr = (x: number) => `Result: ${x}`;\n *\n * const result = pipe(add, double, toStr)(2);\n * // => 'Result: 6'\n * ```\n */\nexport const pipe: Pipe =\n (...fns: PipeFn[]) =>\n (arg: unknown) =>\n fns.reduce((prev, fn) => fn(prev), arg);\n\ntype ComposeFn = (arg: unknown) => unknown;\n\ntype Compose = {\n <A, R>(fn1: (a: A) => R): (a: A) => R;\n <A, B, R>(fn1: (b: B) => R, fn2: (a: A) => B): (a: A) => R;\n <A, B, C, R>(fn1: (c: C) => R, fn2: (b: B) => C, fn3: (a: A) => B): (a: A) => R;\n <A, B, C, D, R>(\n fn1: (d: D) => R,\n fn2: (c: C) => D,\n fn3: (b: B) => C,\n fn4: (a: A) => B,\n ): (a: A) => R;\n <A, B, C, D, E, R>(\n fn1: (e: E) => R,\n fn2: (d: D) => E,\n fn3: (c: C) => D,\n fn4: (b: B) => C,\n fn5: (a: A) => B,\n ): (a: A) => R;\n (...fns: ComposeFn[]): (arg: unknown) => unknown;\n};\n\n/**\n * Composes multiple unary functions into a single function, applying them from **right to left**.\n *\n * Often used for building functional pipelines where the innermost function runs first.\n * Types are inferred up to 5 chained functions for full type safety.\n *\n * @param fns - A list of unary functions to compose.\n *\n * @returns A new function that applies all functions from right to left.\n *\n * @example\n * ```ts\n * const add = (x: number) => x + 1;\n * const double = (x: number) => x * 2;\n * const toStr = (x: number) => `Result: ${x}`;\n *\n * const result = compose(toStr, double, add)(2);\n * // => 'Result: 6'\n * ```\n */\nexport const compose: Compose =\n (...fns: ComposeFn[]) =>\n (arg: unknown) =>\n fns.reduceRight((prev, fn) => fn(prev), arg);\n","export const noop = () => {};\n\n/**\n * Checks if a value is a function.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a function; otherwise, `false`.\n */\nexport const isFunction = (value: unknown) => typeof value === 'function';\n\n/**\n * Creates a function that negates the result of the given predicate function.\n *\n * @template Args - Argument types of the predicate function.\n *\n * @param fn - A function that returns any value.\n *\n * @returns A new function that returns the negated result of the original function.\n *\n * @example\n * ```ts\n * const isEven = (n: number) => n % 2 === 0;\n * const isOdd = not(isEven);\n *\n * console.log(isOdd(2)); // false\n * console.log(isOdd(3)); // true\n * ```\n */\nexport const not =\n <Args extends unknown[]>(fn: (...args: Args) => any): ((...args: Args) => boolean) =>\n (...args: Args) =>\n !fn(...args);\n\n/**\n * Wraps a function so that it can only be executed once.\n * The wrapped function remembers (caches) the result of the first invocation\n * and returns that same result for all subsequent calls, regardless of the arguments provided.\n *\n * Common use cases include:\n * - initializing singletons\n * - running setup logic only once\n * - avoiding repeated expensive computations\n *\n * @template T - A function type whose return value should be cached.\n *\n * @param fn - The function to execute at most once.\n *\n * @returns A new function with the same signature as `fn`, but guaranteed to\n * execute `fn` only on the first call and return the cached result\n * thereafter.\n */\nexport const once = <T extends (...args: any[]) => any>(fn: T): T => {\n let called = false;\n let result: ReturnType<T>;\n\n return function (this: any, ...args: Parameters<T>) {\n if (!called) {\n called = true;\n result = fn.apply(this, args);\n }\n\n return result;\n } as T;\n};\n","import type { Nullable } from '~/types';\nimport { compact } from '~/array';\nimport { isFunction } from '~/function';\n\n/**\n * Checks if a value is a Promise.\n *\n * @template T - The type of the value that the Promise resolves to.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a Promise; otherwise, `false`.\n */\nexport const isPromise = <T = unknown>(value: unknown): value is Promise<T> =>\n isFunction((value as Promise<T>)?.then);\n\n/**\n * Asynchronously iterates over an array and executes an async function on each item sequentially,\n * collecting the results.\n *\n * Useful when order or timing matters (e.g., rate limits, UI updates, animations).\n *\n * @param array - The array of items to iterate over.\n * @param fn - An async function to execute for each item. Must return a value.\n *\n * @returns A promise that resolves with an array of results from each function call.\n *\n * @example\n * ```ts\n * const results = await runSequential([1, 2, 3], async (item) => {\n * await delay(100);\n *\n * return item * 2;\n * });\n *\n * console.log(results); // [2, 4, 6]\n * ```\n */\nexport const runSequential = async <Item, Result>(\n array: Item[],\n fn: (item: Item, index: number, array: Item[]) => Promise<Result>,\n): Promise<Result[]> => {\n const results: Result[] = [];\n\n for (let i = 0; i < array.length; i++) {\n results.push(await fn(array[i], i, array));\n }\n\n return results;\n};\n\n/**\n * Executes an asynchronous operation on each element of an array and waits for all promises to resolve.\n *\n * @param array - The array of items to operate on.\n * @param fn - The asynchronous operation to perform on each item.\n *\n * @returns A promise that resolves with an array of results after all operations are completed.\n *\n * @example\n * ```ts\n * const results = await runParallel([1, 2, 3], async (item) => {\n * await delay(100);\n *\n * return item * 2;\n * });\n *\n * console.log(results); // [2, 4, 6]\n * ```\n */\nexport const runParallel = async <Item, Result>(\n array: Item[],\n fn: (item: Item, index: number, array: Item[]) => Promise<Result>,\n): Promise<Result[]> => Promise.all(array.map(fn));\n\n/**\n * Asynchronously filters an array using a predicate function, executing **sequentially**.\n *\n * Useful for rate-limited or stateful async operations where execution order matters.\n *\n * @template Item - The type of the items in the input array.\n *\n * @param array - The array of items to filter.\n * @param predicate - An async function that returns a `boolean` indicating whether to keep each item.\n *\n * @returns A promise that resolves to a new array containing only the items for which the predicate returned `true`.\n *\n * @example\n * ```ts\n * // Sequentially filter even numbers with delay\n * const result = await filterSequential([1, 2, 3, 4], async (num) => {\n * await delay(100);\n *\n * return num % 2 === 0;\n * });\n *\n * console.log(result); // [2, 4]\n * ```\n */\nexport const filterSequential = async <Item>(\n array: Item[],\n predicate: (item: Item, index: number, array: Item[]) => Promise<boolean>,\n): Promise<Item[]> => {\n const results: Item[] = [];\n\n for (let i = 0; i < array.length; i++) {\n const item = array[i];\n\n if (await predicate(item, i, array)) {\n results.push(item);\n }\n }\n\n return results;\n};\n\n/**\n * Asynchronously filters an array based on a provided async predicate function.\n *\n * Each item is passed to the `predicate` function in parallel, and only the items\n * for which the predicate resolves to `true` are included in the final result.\n *\n * Useful for filtering based on asynchronous conditions such as API calls,\n * file system access, or any other delayed operations.\n *\n * @template Item - The type of the items in the input array.\n *\n * @param array - The array of items to filter.\n * @param predicate - An async function that returns a boolean indicating whether to keep each item.\n *\n * @returns A promise that resolves to a new array containing only the items for which the predicate returned `true`.\n *\n * @example\n * ```ts\n * // Filter numbers that are even after a simulated delay\n * const result = await filterParallel([1, 2, 3, 4], async (num) => {\n * await delay(100);\n *\n * return num % 2 === 0;\n * });\n *\n * console.log(result); // [2, 4]\n * ```\n */\nexport const filterParallel = async <Item>(\n array: Item[],\n predicate: (item: Item, index: number, array: Item[]) => Promise<boolean>,\n): Promise<Item[]> => {\n const results = await runParallel(array, async (item, index, array) =>\n (await predicate(item, index, array)) ? item : false,\n );\n\n return compact(results);\n};\n\n/**\n * Asynchronously checks if at least one element in the array satisfies the async condition.\n *\n * @param array - The array of items to check.\n * @param predicate - An async function that returns a boolean.\n *\n * @returns A promise that resolves to true if any item passes the condition.\n */\nexport const someAsync = async <Item>(\n array: Item[],\n predicate: (item: Item, index: number, array: Item[]) => Promise<boolean>,\n): Promise<boolean> => {\n for (let i = 0; i < array.length; i++) {\n if (await predicate(array[i], i, array)) {\n return true;\n }\n }\n\n return false;\n};\n\n/**\n * Asynchronously checks if all elements in the array satisfy the async condition.\n *\n * @param array - The array of items to check.\n * @param predicate - An async function that returns a boolean.\n *\n * @returns A promise that resolves to true if all items pass the condition.\n */\nexport const everyAsync = async <Item>(\n array: Item[],\n predicate: (item: Item, index: number, array: Item[]) => Promise<boolean>,\n): Promise<boolean> => {\n for (let i = 0; i < array.length; i++) {\n if (!(await predicate(array[i], i, array))) {\n return false;\n }\n }\n\n return true;\n};\n\n/**\n * Asynchronously reduces an array to a single accumulated value.\n *\n * @template Item - The type of items in the array.\n * @template Accumulator - The type of the accumulated result.\n *\n * @param array - The array to reduce.\n * @param fn - The async reducer function that processes each item and returns the updated accumulator.\n * @param initialValue - The initial accumulator value.\n *\n * @returns A promise that resolves to the final accumulated result.\n */\nexport const reduceAsync = async <Item, Accumulator>(\n array: Item[],\n fn: (accumulator: Accumulator, item: Item, index: number, array: Item[]) => Promise<Accumulator>,\n initialValue: Accumulator,\n): Promise<Accumulator> => {\n let accumulator = initialValue;\n\n for (let i = 0; i < array.length; i++) {\n accumulator = await fn(accumulator, array[i], i, array);\n }\n\n return accumulator;\n};\n\n/**\n * Asynchronously finds the first element that satisfies the async condition.\n *\n * @param array - The array of items to search.\n * @param predicate - An async function that returns a boolean.\n *\n * @returns A promise that resolves to the found item or null if none match.\n */\nexport const findAsync = async <Item>(\n array: Item[],\n predicate: (item: Item, index: number, array: Item[]) => Promise<boolean>,\n): Promise<Nullable<Item>> => {\n for (let i = 0; i < array.length; i++) {\n if (await predicate(array[i], i, array)) {\n return array[i];\n }\n }\n\n return null;\n};\n","/**\n * Creates a promise that resolves after the specified delay.\n *\n * Useful for creating artificial delays, implementing timeouts, or spacing operations.\n *\n * @param delayMs - The delay in milliseconds.\n *\n * @returns A promise that resolves after the specified delay.\n *\n * @example\n * ```ts\n * // Wait for 1 second\n * await delay(1000);\n * console.log('This logs after 1 second');\n *\n * // Use with other async operations\n * const fetchWithTimeout = async () => {\n * const timeoutPromise = delay(5000).then(() => {\n * throw new Error('Request timed out');\n * });\n *\n * return Promise.race([fetchData(), timeoutPromise]);\n * }\n * ```\n */\nexport const delay = (delayMs: number): Promise<void> =>\n new Promise(resolve => setTimeout(resolve, delayMs));\n","import type { Nullable, TimeoutId } from '~/types';\nimport { delay } from '~/async';\n\n/**\n * Wraps a promise with a timeout. If the promise does not settle within the specified time,\n * it will reject with a timeout error.\n *\n * @template T - The type of the promise result.\n *\n * @param promise - The promise to wrap.\n * @param timeoutMs - Timeout duration in milliseconds.\n * @param errorMessage - Optional custom error message.\n *\n * @returns A promise that resolves or rejects with the original promise,\n * or rejects with a timeout error if the duration is exceeded.\n *\n * @example\n * ```ts\n * // Rejects if fetch takes longer than 3 seconds\n * const response = await timeout(fetch('/api/data'), 3000);\n *\n * // With custom message\n * await timeout(fetchData(), 2000, 'Too long');\n * ```\n */\nexport const timeout = async <T>(\n promise: Promise<T>,\n timeoutMs: number,\n errorMessage = 'Operation timed out',\n): Promise<T> => {\n const timeoutId: Nullable<TimeoutId> = null;\n\n try {\n return await Promise.race([\n promise,\n delay(timeoutMs).then(() => Promise.reject(new Error(errorMessage))),\n ]);\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n};\n","import { delay } from '~/async';\n\ninterface RetryOptions {\n /**\n * Maximum number of retry attempts before failing.\n *\n * @default 3\n */\n maxAttempts?: number;\n /**\n * Delay in milliseconds between retry attempts.\n * If `backoff` is true, this is the base delay for exponential backoff.\n *\n * @default 300\n */\n delayMs?: number;\n /**\n * Whether to use exponential backoff for delays between attempts.\n * When enabled, the delay is multiplied by 2 ^ (`attempt` - 1).\n *\n * @default true\n */\n backoff?: boolean;\n /**\n * Optional callback triggered before each retry attempt.\n *\n * @param attempt - The current attempt number (starting from 1).\n * @param error - The error that caused the retry.\n */\n onRetry?: (attempt: number, error: unknown) => void;\n}\n\n/**\n * Wraps an asynchronous function with retry logic.\n *\n * The returned function will attempt to call the original function up to `maxAttempts` times,\n * with a delay between retries. If all attempts fail, the last encountered error is thrown.\n *\n * Useful for operations that may fail intermittently, such as network requests.\n *\n * @template Task - The type of the async function to wrap.\n * @template TaskResult - The result type of the async function.\n *\n * @param task - The async function to wrap with retry logic.\n * @param options - Configuration options for retry behavior.\n *\n * @returns A function that wraps the original function with retry support.\n *\n * @example\n * ```ts\n * async function fetchData() {\n * const response = await fetch('/api/data');\n *\n * if (!response.ok) {\n * throw new Error('Network error');\n * }\n *\n * return await response.json();\n * }\n *\n * const fetchWithRetry = retry(fetchData, {\n * maxAttempts: 5,\n * delayMs: 500,\n * onRetry: (attempt, error) => {\n * console.warn(`Attempt ${attempt} failed:`, error);\n * }\n * });\n *\n * fetchWithRetry()\n * .then(data => console.log('Success:', data))\n * .catch(error => console.error('Failed after retries:', error));\n * ```\n */\nexport const retry = <Task extends (...args: unknown[]) => Promise<TaskResult>, TaskResult>(\n task: Task,\n { maxAttempts = 3, delayMs = 300, backoff = true, onRetry }: RetryOptions = {},\n): ((...args: Parameters<Task>) => Promise<TaskResult>) => {\n return async (...args: Parameters<Task>): Promise<TaskResult> => {\n let lastError: unknown;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await task(...args);\n } catch (e) {\n lastError = e;\n\n if (attempt < maxAttempts) {\n onRetry?.(attempt, e);\n\n const delayTime = backoff ? delayMs * 2 ** (attempt - 1) : delayMs;\n await delay(delayTime);\n }\n }\n }\n\n throw lastError;\n };\n};\n","/**\n * Checks if a value is a string.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a string; otherwise, `false`.\n */\nexport const isString = (value: unknown): value is string => typeof value === 'string';\n","import { isString } from '~/string';\nimport { assert, isUndefined } from '~/guards';\n\nexport type Downloadable = Blob | MediaSource | string;\n\nexport interface DownloadFileOptions {\n /**\n * Suggested filename for the downloaded file.\n *\n * When provided, the browser will attempt to save the file using this name.\n * If omitted and the source is a URL string, the browser may infer the name\n * from the URL.\n */\n fileName?: string;\n /**\n * Target browsing context for the download link.\n */\n target?: '_self' | '_blank';\n}\n\n/**\n * Initiates a file download in a browser environment.\n *\n * This utility supports downloading from:\n * - a URL string\n * - a `Blob`\n * - a `MediaSource`\n *\n * For non-string inputs, an object URL is created temporarily and\n * automatically revoked after the download is triggered.\n *\n * @remarks\n * - This function performs direct DOM manipulation and must be executed in a browser environment.\n * - In non-DOM contexts (e.g. SSR), the function exits without side effects.\n * - Object URLs are revoked asynchronously to avoid Safari-related issues.\n *\n * @param file - The file source to download (URL string or binary object).\n * @param options - Optional configuration controlling filename and link target.\n */\nexport const downloadFile = (\n file: Downloadable,\n { fileName, target }: DownloadFileOptions = {},\n): void => {\n // Browser guard (SSR / non-DOM environments)\n if (isUndefined(document)) {\n return;\n }\n\n const link = document.createElement('a');\n let objectUrl: string | null = null;\n\n try {\n const href = isString(file) ? file : (objectUrl = URL.createObjectURL(file));\n link.href = href;\n\n if (fileName) {\n link.download = fileName;\n }\n\n if (target) {\n link.target = target;\n }\n\n // Required for Firefox / Safari\n document.body.appendChild(link);\n link.click();\n } finally {\n link.remove();\n\n if (objectUrl) {\n // Delay revocation to avoid Safari issues\n setTimeout(() => {\n assert(objectUrl, 'Object URL should not be null');\n\n URL.revokeObjectURL(objectUrl);\n }, 0);\n }\n }\n};\n","/**\n * Checks whether an element has horizontal overflow.\n *\n * @param element - The element to check.\n *\n * @returns `true` if the content overflows horizontally.\n */\nexport const hasXOverflow = (element: HTMLElement): boolean =>\n element.scrollWidth > element.clientWidth;\n\n/**\n * Calculates the horizontal overflow width of an element.\n *\n * The overflow width represents how much wider the content is compared\n * to the visible container area.\n *\n * @param element - The scrollable container element.\n *\n * @returns The overflow width in pixels. Returns `0` when the content does not overflow horizontally.\n */\nexport const getXOverflowWidth = (element: HTMLElement): number =>\n Math.max(0, element.scrollWidth - element.clientWidth);\n\n/**\n * Checks whether an element has vertical overflow.\n *\n * @param element - The element to check.\n *\n * @returns `true` if the content overflows vertically.\n */\nexport const hasYOverflow = (element: HTMLElement): boolean =>\n element.scrollHeight > element.clientHeight;\n\n/**\n * Calculates the vertical overflow height of an element.\n *\n * The overflow height represents how much taller the content is compared\n * to the visible container area.\n *\n * @param element - The scrollable container element.\n *\n * @returns The overflow height in pixels. Returns `0` when the content does not overflow vertically.\n */\nexport const getYOverflowHeight = (element: HTMLElement): number =>\n Math.max(0, element.scrollHeight - element.clientHeight);\n","export interface CalculateCenterOffsetOptions {\n /**\n * Total overflow size for the axis.\n *\n * Represents how much larger the content is compared to the visible\n * container size (e.g. scroll width minus client width).\n */\n overflowSize: number;\n /**\n * Visible size of the container along the axis.\n *\n * Typically, `clientWidth` for the X axis or `clientHeight` for the Y axis.\n */\n containerSize: number;\n /**\n * Offset of the target element from the start of the container along the axis.\n *\n * Typically, `offsetLeft` (X axis) or `offsetTop` (Y axis).\n */\n elementOffset: number;\n /**\n * Size of the target element along the axis.\n *\n * Typically, `clientWidth` (X axis) or `clientHeight` (Y axis).\n */\n elementSize: number;\n}\n\n/**\n * Calculates the offset required to center an element within a container along a single axis.\n *\n * The returned value is clamped so that the resulting translation does not\n * exceed the container's scrollable bounds.\n *\n * This function performs pure math only and does not access the DOM.\n *\n * @returns A negative offset value suitable for use in a CSS `translate`\n * transform, or `0` when no overflow exists on the axis.\n */\nexport const calculateCenterOffset = ({\n overflowSize,\n containerSize,\n elementOffset,\n elementSize,\n}: CalculateCenterOffsetOptions): number => {\n if (overflowSize <= 0) {\n return 0;\n }\n\n const containerCenter = containerSize / 2;\n const elementCenter = elementOffset + elementSize / 2;\n\n const targetOffset = elementCenter - containerCenter;\n\n return -Math.max(0, Math.min(targetOffset, overflowSize));\n};\n","import { getXOverflowWidth, getYOverflowHeight } from '~/dom';\nimport { calculateCenterOffset } from '~/geometry';\n\ntype Axis = 'x' | 'y' | 'both';\n\nexport interface CenterElementInContainerOptions {\n /**\n * Axis (or axes) along which centering is applied.\n *\n * @default 'both'\n */\n axis?: Axis;\n}\n\n/**\n * Translates a container so that a target element is visually centered within its visible bounds.\n *\n * Centering is achieved by applying a CSS `transform: translate(...)` to the\n * container element rather than using native scrolling.\n *\n * ### Behavior\n * - Centering is calculated independently for each enabled axis.\n * - Translation is applied only when the container content overflows on that axis.\n * - When no overflow exists, the container remains untransformed for that axis.\n *\n * ### Notes\n * - This function performs immediate DOM reads and writes.\n * - The resulting transform is clamped to valid scrollable bounds.\n *\n * @param containerElement - The container whose content is translated.\n * @param elementToCenter - The descendant element to align to the container’s center.\n * @param options - Optional configuration controlling which axis or axes are centered.\n */\nexport const centerElementInContainer = (\n containerElement: HTMLElement,\n elementToCenter: HTMLElement,\n { axis = 'both' }: CenterElementInContainerOptions = {},\n): void => {\n let translateX = 0;\n let translateY = 0;\n\n if (axis === 'x' || axis === 'both') {\n translateX = calculateCenterOffset({\n overflowSize: getXOverflowWidth(containerElement),\n containerSize: containerElement.clientWidth,\n elementOffset: elementToCenter.offsetLeft,\n elementSize: elementToCenter.clientWidth,\n });\n }\n\n if (axis === 'y' || axis === 'both') {\n translateY = calculateCenterOffset({\n overflowSize: getYOverflowHeight(containerElement),\n containerSize: containerElement.clientHeight,\n elementOffset: elementToCenter.offsetTop,\n elementSize: elementToCenter.clientHeight,\n });\n }\n\n containerElement.style.transform = `translate(${translateX}px, ${translateY}px)`;\n};\n","interface HTMLElementTransformationValues {\n translateX: number;\n translateY: number;\n scaleX: number;\n scaleY: number;\n skewX: number;\n skewY: number;\n}\n\n/**\n * Extracts transformation values (translate, scale, skew) from the 2D transformation matrix of a given HTML element.\n *\n * Only works with 2D transforms (i.e., `matrix(a, b, c, d, e, f)`).\n *\n * @param element - The element with a CSS transform applied.\n * @returns An object with parsed transformation values.\n *\n * @example\n * ```ts\n * const values = parse2DMatrix(myElement);\n * console.log(values.translateX);\n * console.log(values.scaleX);\n * ```\n */\nexport const parse2DMatrix = (element: HTMLElement): HTMLElementTransformationValues => {\n const computedStyles = window.getComputedStyle(element);\n const transformValue = computedStyles.getPropertyValue('transform');\n\n const matrixMatch = transformValue.match(/^matrix\\((.+)\\)$/);\n if (!matrixMatch) {\n return {\n translateX: 0,\n translateY: 0,\n scaleX: 1,\n scaleY: 1,\n skewX: 0,\n skewY: 0,\n };\n }\n\n const [scaleX, skewY, skewX, scaleY, translateX, translateY] = matrixMatch[1]\n .split(', ')\n .map(parseFloat);\n\n return {\n translateX,\n translateY,\n scaleX,\n scaleY,\n skewX,\n skewY,\n };\n};\n","/**\n * Determines whether the browser environment allows safe read access to\n * `localStorage`. Some platforms (e.g., Safari Private Mode, sandboxed iframes)\n * expose `localStorage` but still throw when accessed.\n *\n * This function **only tests read access**, making it safe even when write\n * operations would fail due to `QuotaExceededError` or storage restrictions.\n *\n * @returns `true` if `localStorage` exists and calling `getItem()` does not\n * throw; otherwise `false`.\n */\nexport const isLocalStorageReadable = (): boolean => {\n if (typeof window === 'undefined' || !window.localStorage) {\n return false;\n }\n\n try {\n window.localStorage.getItem('__non_existing_key__');\n return true;\n } catch {\n return false;\n }\n};\n\ninterface LocalStorageCapabilities {\n readable: boolean;\n writable: boolean;\n}\n\ninterface LocalStorageCapabilities {\n readable: boolean;\n writable: boolean;\n}\n\n/**\n * Determines whether the browser's `localStorage` supports safe read and write operations.\n * This function performs two independent checks:\n *\n * **1. Readability**\n * - Verified by calling `localStorage.getItem()` inside a `try` block.\n * - Fails in environments where storage access throws immediately (e.g., disabled storage,\n * sandboxed iframes, strict privacy modes, SSR).\n *\n * **2. Writeability**\n * - Verified by attempting to `setItem()` and then `removeItem()` using a temporary key.\n * - Can fail due to:\n * - `QuotaExceededError` when storage is full.\n * - Disabled write access (e.g., Safari Private Mode).\n * - Security-restricted contexts (third-party frames, hardened privacy settings)\n *\n * @returns An object describing the detected `localStorage` capabilities.\n */\nexport const getLocalStorageCapabilities = (): LocalStorageCapabilities => {\n const readable = isLocalStorageReadable();\n if (!readable) {\n return {\n readable: false,\n writable: false,\n };\n }\n\n try {\n const key = '__test_write__';\n\n window.localStorage.setItem(key, '1');\n window.localStorage.removeItem(key);\n\n return {\n readable: true,\n writable: true,\n };\n } catch {\n // Readable but not writable (QuotaExceededError, private mode, security restrictions)\n }\n\n return {\n readable: true,\n writable: false,\n };\n};\n","import type { Nullable } from '~/types';\nimport { runParallel } from '~/async';\n\n/**\n * Checks if a value is a `File` object.\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is a `File` object; otherwise, `false`.\n */\nexport const isFile = (value: unknown): value is File => value instanceof File;\n\n/**\n * Converts a `FileList` object to an array of `File` objects.\n *\n * @param fileList - The `FileList` object to convert.\n *\n * @returns An array of `File` objects.\n */\nexport const fileListToFiles = (fileList: Nullable<FileList>): File[] => {\n if (!fileList) {\n return [];\n }\n\n const files: File[] = [];\n\n for (let i = 0; i < fileList.length; i++) {\n files.push(fileList[i]);\n }\n\n return files;\n};\n\n/**\n * Converts a `Blob` object into a `File` object with the specified name.\n *\n * This is useful when you receive a `Blob` (e.g., from canvas, fetch, or file manipulation)\n * and need to convert it into a `File` to upload via `FormData` or file inputs.\n *\n * @param blob - The `Blob` to convert.\n * @param fileName - The desired name for the resulting file (including extension).\n *\n * @returns A `File` instance with the same content and MIME type as the input `Blob`.\n *\n * @example\n * ```ts\n * const blob = new Blob(['Hello world'], { type: 'text/plain' });\n * const file = blobToFile(blob, 'hello.txt');\n *\n * console.log(file instanceof File); // true\n * ```\n */\nexport const blobToFile = (blob: Blob, fileName: string): File =>\n new File([blob], fileName, {\n type: blob.type,\n });\n\n/**\n * Reads all entries from a file system directory asynchronously.\n *\n * @param directoryEntry - The directory entry to read.\n *\n * @returns A promise that resolves to all `FileSystemEntry` items in the directory.\n */\nconst readFileSystemDirectoryEntries = async (\n directoryEntry: FileSystemDirectoryEntry,\n): Promise<FileSystemEntry[]> => {\n const directoryReader = directoryEntry.createReader();\n\n const readAll = async (): Promise<FileSystemEntry[]> =>\n new Promise((resolve, reject) => {\n directoryReader.readEntries(async entries => {\n if (!entries.length) {\n resolve([]);\n return;\n }\n\n try {\n const restEntries = await readAll();\n\n resolve([...entries, ...restEntries]);\n } catch (e) {\n reject(e);\n }\n }, reject);\n });\n\n return readAll();\n};\n\ninterface TraverseDirectoryOptions {\n /**\n * A list of file names that should be ignored during traversal.\n * Any file whose name matches an entry will be skipped entirely.\n *\n * Common values include OS-generated metadata files such as:\n * `.DS_Store`, `Thumbs.db`, `desktop.ini`, `.Spotlight-V100`, etc.\n */\n skipFiles?: string[];\n}\n\n/**\n * Recursively scans a directory using the File System API and collects all nested files.\n *\n * This function walks through all subdirectories, resolving each file into a `File` object.\n * Directories themselves are not returned. To avoid unnecessary noise, certain system or\n * OS-generated files can be excluded via the `skipFiles` option.\n *\n * @param directoryEntry - The starting directory entry to traverse.\n * @param options - Optional settings that control traversal behavior.\n *\n * @returns A promise resolving to a flat array of all collected `File` objects.\n */\nexport const traverseFileSystemDirectory = async (\n directoryEntry: FileSystemDirectoryEntry,\n {\n skipFiles = [\n '.DS_Store',\n 'Thumbs.db',\n 'desktop.ini',\n 'ehthumbs.db',\n '.Spotlight-V100',\n '.Trashes',\n '.fseventsd',\n '__MACOSX',\n ],\n }: TraverseDirectoryOptions = {},\n): Promise<File[]> => {\n const skipFilesSet = new Set(skipFiles);\n const entries = await readFileSystemDirectoryEntries(directoryEntry);\n\n const filePromises = await runParallel(entries, async entry => {\n if (entry.isDirectory) {\n return traverseFileSystemDirectory(entry as FileSystemDirectoryEntry, {\n skipFiles,\n });\n } else if (!skipFilesSet.has(entry.name)) {\n const file = await new Promise<File>((resolve, reject) => {\n (entry as FileSystemFileEntry).file(resolve, reject);\n });\n\n return [file];\n }\n\n return [];\n });\n\n return filePromises.flat();\n};\n\n/**\n * Reads files from a `DataTransfer` object, supporting both individual files\n * and entire directories (when available through the non-standard `webkitGetAsEntry` API).\n *\n * This function is typically used in drag-and-drop or paste handlers to obtain\n * all `File` objects contained in the user's action. When directories are dropped,\n * they are traversed recursively using `traverseFileSystemDirectory`, returning a\n * fully flattened list of nested files.\n *\n * @param dataTransfer - The `DataTransfer` instance from a drop or paste event.\n * If `null` or missing items, an empty array is returned.\n * @param traverseOptions - Optional settings passed to directory traversal.\n *\n * @returns A promise that resolves to a flat array of all extracted `File` objects.\n * This includes:\n * - direct files from the drag event,\n * - files extracted from directory entries via `webkitGetAsEntry`,\n * - and files found recursively within nested subdirectories.\n */\nexport const readFilesFromDataTransfer = async (\n dataTransfer: Nullable<DataTransfer>,\n traverseOptions: TraverseDirectoryOptions = {},\n) => {\n const items = dataTransfer?.items;\n if (!items) {\n return [];\n }\n\n const tasks: Promise<File[]>[] = [];\n\n for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {\n const item = items[itemIndex];\n\n // Prefer using webkitGetAsEntry when available (directory support)\n // https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/webkitGetAsEntry#browser_compatibility\n if ('webkitGetAsEntry' in item) {\n // ?.() -> avoids throwing on Safari weirdness\n const entry = item.webkitGetAsEntry?.();\n\n if (entry?.isDirectory) {\n tasks.push(traverseFileSystemDirectory(entry as FileSystemDirectoryEntry, traverseOptions));\n\n continue;\n }\n\n if (entry?.isFile) {\n tasks.push(\n new Promise<File[]>((resolve, reject) =>\n (entry as FileSystemFileEntry).file(file => resolve([file]), reject),\n ),\n );\n\n continue;\n }\n }\n\n // Fallback to standard API\n const file = item.getAsFile();\n if (file) {\n tasks.push(Promise.resolve([file]));\n }\n }\n\n return (await Promise.all(tasks)).flat();\n};\n","/**\n * Invokes the given input if it is a function, passing the provided arguments.\n * Otherwise, returns the input as-is.\n *\n * @template Args - Tuple of argument types to pass to the function.\n * @template Result - Return type of the function or the value.\n *\n * @param input - A function to invoke with `args`, or a direct value of type `Result`.\n * @param args - Arguments to pass if `input` is a function.\n *\n * @returns The result of invoking the function, or the original value if it's not a function.\n */\nexport const invokeIfFunction = <Args extends unknown[], Result>(\n input: ((...args: Args) => Result) | Result,\n ...args: Args\n): Result => (typeof input === 'function' ? (input as (...args: Args) => Result)(...args) : input);\n","import type { Nullable } from '~/types';\n\ninterface ResolveBoundedDeltaOptions {\n /**\n * Incremental change to apply to the current value.\n *\n * The sign of this value determines the direction of movement:\n * - Negative values move toward the minimum bound\n * - Positive values move toward the maximum bound\n */\n delta: number;\n /**\n * Current numeric value before applying the delta.\n */\n value: number;\n /**\n * Minimum allowed value (inclusive).\n *\n * Movement beyond this boundary is prevented.\n */\n min: number;\n /**\n * Maximum allowed value (inclusive).\n *\n * Movement beyond this boundary is prevented.\n */\n max: number;\n}\n\n/**\n * Resolves the next value by consuming a delta within fixed numeric bounds.\n *\n * This function applies **bounded delta consumption** rather than naive clamping:\n *\n * - The delta is applied in the given direction as long as movement is possible.\n * - If the delta would overshoot a bound, it is partially consumed so the\n * resulting value lands exactly on the boundary.\n * - If movement in the given direction is no longer possible, `null` is returned.\n *\n * This behavior mirrors how native scroll engines and drag constraints\n * handle fast input without jitter or overshoot.\n *\n * ### Key characteristics\n * - Direction-aware (positive and negative deltas behave independently)\n * - Prevents overshoot while preserving remaining movement\n * - Does **not** clamp unconditionally\n * - Side-effect free and fully deterministic\n *\n * ### Common use cases\n * - Synthetic scrolling\n * - Drag constraints\n * - Sliders and carousels\n * - Timelines and scrubbers\n * - Inertia and momentum systems\n *\n * @param delta - Incremental change to apply to the current value.\n * The sign determines the movement direction.\n * @param value - Current numeric value before applying the delta.\n * @param min - Minimum allowed value (inclusive).\n * @param max - Maximum allowed value (inclusive).\n *\n * @returns The next resolved value after applying the delta,\n * or `null` if movement in the given direction is not possible.\n *\n * @example\n * ```ts\n * // Simple bounded movement\n * resolveBoundedDelta({ value: 10, delta: -5, min: 0, max: 100 });\n * // → 5\n *\n * // Overshoot is clamped to the boundary\n * resolveBoundedDelta({ value: 2, delta: -10, min: 0, max: 100 });\n * // → 0\n *\n * // Movement blocked at the boundary\n * resolveBoundedDelta({ value: 0, delta: -5, min: 0, max: 100 });\n * // → null\n * ```\n */\nexport const resolveBoundedDelta = ({\n delta,\n value,\n min,\n max,\n}: ResolveBoundedDeltaOptions): Nullable<number> => {\n if (delta === 0) {\n return null;\n }\n\n const candidate = value + delta;\n\n if (delta < 0) {\n return value <= min ? null : Math.max(candidate, min);\n }\n\n if (delta > 0) {\n return value >= max ? null : Math.min(candidate, max);\n }\n\n return null;\n};\n","import type { Nullable } from '~/types';\nimport { resolveBoundedDelta } from '~/geometry';\n\nexport interface InertiaOptions {\n /**\n * Current velocity of the inertial motion.\n *\n * Expressed in **pixels per millisecond (`px/ms`)**.\n *\n * The sign determines direction:\n * - Positive → movement toward the upper bound\n * - Negative → movement toward the lower bound\n */\n velocityPxMs: number;\n /**\n * Time elapsed since the previous inertia step, in milliseconds.\n */\n deltaTimeMs: number;\n /**\n * Exponential friction coefficient controlling velocity decay.\n *\n * Friction is applied per millisecond using an exponential model:\n *\n * `velocityPxMs *= exp(-friction * deltaTimeMs)`\n *\n * Smaller values result in longer, floatier inertia;\n * larger values cause quicker deceleration.\n *\n * Typical values:\n * - `0.001` — very long, floaty inertia\n * - `0.002` — balanced, natural decay (default)\n * - `0.005` — short, snappy stop\n *\n * @default 0.002\n */\n friction?: number;\n /**\n * Minimum absolute velocity below which inertia is considered complete.\n *\n * When `|velocityPxMs| < minVelocityPxMs`, inertia terminates and no further movement is applied.\n *\n * This prevents unnecessary micro-updates and visual jitter near rest.\n *\n * @default 0.01\n */\n minVelocityPxMs?: number;\n /**\n * Exponential Moving Average (EMA) factor used to smooth velocity changes.\n *\n * This is applied **after friction**, blending the previous velocity\n * with the newly decayed velocity to reduce jitter and sudden spikes.\n *\n * Value range: `0..1`\n *\n * - `0` → EMA disabled (raw exponential decay only)\n * - `0.2` → light smoothing (recommended for scroll / drag inertia)\n * - `0.5` → heavy smoothing (very soft, less responsive)\n *\n * Formula:\n * `vNext = vPrev * (1 - emaAlpha) + vDecayed * emaAlpha`\n *\n * @default 0.2\n */\n emaAlpha?: number;\n}\n\ninterface ApplyInertiaStepOptions extends InertiaOptions {\n /**\n * Current numeric value before applying the inertia step.\n *\n * This commonly represents a translated position\n * (e.g. scroll offset or `translateX` value),\n * but may be any numeric value constrained by bounds.\n */\n value: number;\n /**\n * Lower bound for the value (inclusive).\n */\n min: number;\n /**\n * Upper bound for the value (inclusive).\n */\n max: number;\n}\n\n/**\n * Result of a single inertia simulation step.\n *\n * Returned when inertia is still active and further movement in the current direction is possible.\n */\nexport interface InertiaStepResult {\n /**\n * Updated value after applying this inertia step.\n *\n * Guaranteed to be within `[min, max]`.\n */\n value: number;\n /**\n * Updated velocity after friction decay and optional EMA smoothing.\n *\n * Expressed in pixels per millisecond (`px/ms`).\n */\n velocityPxMs: number;\n}\n\n/**\n * Applies a **single step** of bounded, velocity-based inertia.\n *\n * This function models **momentum-driven motion** by:\n * - integrating velocity over elapsed time\n * - applying exponential friction\n * - optionally smoothing velocity using EMA\n * - enforcing hard bounds via {@link resolveBoundedDelta}\n *\n * Boundary handling guarantees:\n * - no overshoot\n * - no oscillation at limits\n * - deterministic stopping behavior\n *\n * ---\n *\n * ### Termination conditions\n * Inertia ends immediately when:\n * - the absolute velocity falls below `minVelocityPxMs`, or\n * - movement in the current direction is blocked by a bound\n *\n * ---\n *\n * ⚠️ **Single-step function**\n * This function advances inertia **once only**.\n * It must be invoked repeatedly from an animation loop\n * (e.g. `requestAnimationFrame`) to produce continuous motion.\n *\n * ---\n *\n * ### Common use cases\n * - Synthetic scrolling with momentum\n * - Drag-to-scroll interactions\n * - Carousels and sliders\n * - Timelines and scrubbers\n *\n * @returns An {@link InertiaStepResult} while inertia remains active,\n * or `null` when inertia has completed or cannot proceed.\n */\nexport const applyInertiaStep = ({\n value,\n min,\n max,\n velocityPxMs,\n deltaTimeMs,\n friction = 0.002,\n minVelocityPxMs = 0.01,\n emaAlpha = 0.2,\n}: ApplyInertiaStepOptions): Nullable<InertiaStepResult> => {\n if (Math.abs(velocityPxMs) < minVelocityPxMs) {\n return null;\n }\n\n const nextValue = resolveBoundedDelta({\n delta: velocityPxMs * deltaTimeMs,\n value,\n min,\n max,\n });\n\n // Hit a hard bound → stop inertia immediately\n if (nextValue === null) {\n return null;\n }\n\n /**\n * Apply exponential friction.\n * The exponent is **negative** because friction must continuously *reduce* velocity over time.\n */\n const decay = Math.exp(-friction * deltaTimeMs);\n const pureVelocityPxMs = velocityPxMs * decay;\n\n const nextVelocityPxMs =\n emaAlpha > 0 ? velocityPxMs * (1 - emaAlpha) + pureVelocityPxMs * emaAlpha : pureVelocityPxMs;\n\n if (Math.abs(nextVelocityPxMs) < minVelocityPxMs) {\n return null;\n }\n\n return {\n value: nextValue,\n velocityPxMs: nextVelocityPxMs,\n };\n};\n","/**\n * Generates a lightweight, ephemeral identifier for short-lived, client-side use.\n *\n * The identifier combines a high-resolution timestamp with a\n * pseudo-random suffix to reduce collision probability.\n *\n * ⚠️ Uniqueness is **best-effort only**:\n * - No guarantee of global uniqueness\n * - Not suitable for persistence or cross-session usage\n * - Not safe for security-sensitive or externally visible identifiers\n *\n * Intended use cases:\n * - Temporary UI keys (e.g. React lists, animations)\n * - In-memory references scoped to a single runtime\n *\n * @returns An ephemeral string identifier.\n */\nexport const generateEphemeralId = (): string => {\n const timestampPart = Math.floor(performance.now() * 1000).toString(36);\n const randomPart = Math.random().toString(36).slice(2, 10);\n\n return `${timestampPart}${randomPart}`;\n};\n","/**\n * Calculates the intersection ratio between two DOM rectangles.\n *\n * The ratio represents the proportion of the `targetRect` that is covered by `sourceRect`.\n * A value of `1` means `sourceRect` completely covers `targetRect`, and `0` means no overlap.\n *\n * @param sourceRect - The rectangle used to measure overlap against the target.\n * @param targetRect - The rectangle whose covered area is measured.\n *\n * @returns A number between `0` and `1` representing the intersection ratio.\n */\nexport const getDOMRectIntersectionRatio = (sourceRect: DOMRect, targetRect: DOMRect): number => {\n const xOverlap = Math.max(\n 0,\n Math.min(sourceRect.right, targetRect.right) - Math.max(sourceRect.left, targetRect.left),\n );\n\n const yOverlap = Math.max(\n 0,\n Math.min(sourceRect.bottom, targetRect.bottom) - Math.max(sourceRect.top, targetRect.top),\n );\n\n const intersectionArea = xOverlap * yOverlap;\n const targetArea = targetRect.width * targetRect.height;\n\n return intersectionArea / targetArea;\n};\n","export type Axis = 'x' | 'y' | 'both';\n\n/**\n * Values typically originate from wheel, drag, touch, or other pointer-based input sources.\n */\nexport interface AxisDelta {\n deltaX: number;\n deltaY: number;\n}\n\nexport interface ResolveAxisDeltaOptions {\n /**\n * Whether vertical input may be used as a fallback source\n * for horizontal movement when no horizontal delta is present.\n *\n * This is especially useful for mouse wheels that emit only\n * vertical deltas while scrolling horizontal content (e.g. tab lists or carousels).\n *\n * @default true\n */\n allowFallback?: boolean;\n /**\n * Whether to invert the resolved delta direction.\n *\n * Inversion is commonly required for synthetic scrolling,\n * where positive input deltas should move content in the\n * opposite direction of the pointer or wheel movement.\n *\n * @default true\n */\n invert?: boolean;\n}\n\n/**\n * Resolves a raw two-dimensional input delta into an axis-aligned delta\n * according to the specified axis and resolution rules.\n *\n * This function is input-agnostic and does not perform any DOM mutations.\n * It is intended to be used as a normalization step for wheel, drag,\n * touch, or other pointer-based input before applying scroll physics.\n *\n * ### Resolution rules\n * - `'x'`:\n * - Uses horizontal input when available.\n * - Optionally falls back to vertical input when horizontal input is zero.\n * - `'y'`:\n * - Uses vertical input only.\n * - `'both'`:\n * - Preserves both horizontal and vertical input.\n *\n * ### Direction handling\n * - When `invert` is enabled, the resolved delta direction is inverted\n * to match typical synthetic scrolling behavior.\n *\n * @param delta - Raw input movement delta.\n * @param axis - Axis along which movement should be resolved.\n * @param options - Resolution behavior configuration.\n *\n * @returns A normalized, axis-aligned delta suitable for further scroll or movement processing.\n */\nexport const resolveAxisDelta = (\n delta: AxisDelta,\n axis: Axis,\n { allowFallback = true, invert = true }: ResolveAxisDeltaOptions = {},\n): AxisDelta => {\n const sign = invert ? -1 : 1;\n\n switch (axis) {\n case 'x': {\n const value = delta.deltaX !== 0 ? delta.deltaX : allowFallback ? delta.deltaY : 0;\n\n return {\n deltaX: sign * value,\n deltaY: 0,\n };\n }\n\n case 'y':\n return {\n deltaX: 0,\n deltaY: sign * delta.deltaY,\n };\n\n default:\n return {\n deltaX: sign * delta.deltaX,\n deltaY: sign * delta.deltaY,\n };\n }\n};\n","/**\n * Calculates the Euclidean distance between two points in 2D space.\n *\n * @param startX - The X coordinate of the starting point.\n * @param startY - The Y coordinate of the starting point.\n * @param endX - The X coordinate of the ending point.\n * @param endY - The Y coordinate of the ending point.\n *\n * @returns The Euclidean distance between the two points.\n */\nexport const calculateEuclideanDistance = (\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n): number => {\n const deltaX = endX - startX;\n const deltaY = endY - startY;\n\n return Math.hypot(deltaX, deltaY);\n};\n\n/**\n * Calculates the moving speed.\n *\n * @param distance - The distance.\n * @param elapsedTime - The time taken to move the distance.\n *\n * @returns The calculated speed, which is the absolute value of delta divided by elapsed time.\n */\nexport const calculateMovingSpeed = (distance: number, elapsedTime: number): number =>\n Math.abs(distance / elapsedTime);\n\n/**\n * Calculates the specified percentage of a given value.\n *\n * @param value - The value to calculate the percentage of.\n * @param percentage - The percentage to calculate.\n *\n * @returns The calculated percentage of the value.\n */\nexport const calculatePercentage = (value: number, percentage: number): number =>\n (value * percentage) / 100;\n","/**\n * Generates a short, consistent hash string from an input string using a DJB2-inspired algorithm.\n *\n * This function uses a variation of the DJB2 algorithm, which is a simple yet effective hashing algorithm\n * based on bitwise XOR (`^`) and multiplication by 33. It produces a non-negative 32-bit integer,\n * which is then converted to a base-36 string (digits + lowercase letters) to produce a compact output.\n *\n * Useful for:\n * - Generating stable class names in CSS-in-JS libraries.\n * - Producing consistent cache keys.\n * - Quick and lightweight hashing needs where cryptographic security is not required.\n *\n * ⚠️ This is not cryptographically secure and should not be used for hashing passwords or sensitive data.\n *\n * @param input - The input string to hash.\n *\n * @returns A short, base-36 encoded hash string.\n *\n * @example\n * ```ts\n * const className = hashString('background-color: red;');\n * // → 'e4k1z0x'\n * ```\n */\nexport const hashString = (input: string): string => {\n let hash = 5381;\n\n for (let i = 0; i < input.length; i++) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n\n return (hash >>> 0).toString(36);\n};\n","export type DefinedProps<T extends object> = {\n [K in keyof T as T[K] extends undefined ? never : K]: Exclude<T[K], undefined>;\n};\n\n/**\n * Create a new object by removing properties whose values are `undefined`.\n *\n * Example:\n * ```ts\n * definedProps({ a: 1, b: undefined, c: 'x' });\n * // -> { a: number; c: string }\n * ```\n *\n * @template T - Input object shape.\n *\n * @param obj - The source object to clean.\n *\n * @returns A new object containing only keys whose runtime values are not `undefined`.\n */\nexport const definedProps = <T extends object>(obj: T): DefinedProps<T> =>\n Object.entries(obj).reduce((result, [key, value]) => {\n if (value !== undefined) {\n result[key] = value;\n }\n\n return result;\n }, {} as any);\n","/**\n * Converts a string to kebab-case format.\n *\n * This function transforms camelCase or PascalCase strings into kebab-case by inserting\n * hyphens between lowercase and uppercase letters, then converting everything to lowercase.\n *\n * @param input - The string to convert to kebab-case.\n *\n * @returns The kebab-case formatted string.\n *\n * @example\n * ```ts\n * toKebabCase('helloWorld'); // → 'hello-world'\n * toKebabCase('HelloWorld'); // → 'hello-world'\n * toKebabCase('hello123World'); // → 'hello123-world'\n * ```\n */\nexport const toKebabCase = (input: string): string =>\n input.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n","/**\n * Converts a camelCase string to dash-case format.\n *\n * This function transforms camelCase strings into dash-case by inserting\n * hyphens before uppercase letters and converting them to lowercase.\n * The function ensures that no hyphen is added at the start of the output string,\n * even if the input begins with an uppercase letter.\n *\n * @param input - The camelCase string to convert to dash-case.\n *\n * @returns The dash-case formatted string.\n *\n * @example\n * ```ts\n * camelToDashCase('helloWorld'); // → 'hello-world'\n * camelToDashCase('HelloWorld'); // → 'hello-world'\n * camelToDashCase('backgroundColor'); // → 'background-color'\n * ```\n */\nexport const camelToDashCase = (input: string): string => {\n // First handle the first character separately to avoid adding a hyphen at the start\n const firstChar = input.charAt(0);\n const restOfString = input.slice(1);\n\n // Convert the first character to the lowercase without adding a hyphen\n const firstCharProcessed = firstChar.toLowerCase();\n\n // Process the rest of the string normally, adding hyphens before uppercase letters\n const restProcessed = restOfString.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);\n\n return firstCharProcessed + restProcessed;\n};\n","/**\n * Splits a camelCase or PascalCase string into separate words with spaces.\n *\n * This function inserts spaces between lowercase and uppercase letters,\n * making camelCase or PascalCase strings more human-readable without\n * altering their original capitalization.\n *\n * @param input - The camelCase or PascalCase string to split into words.\n *\n * @returns The string with spaces inserted between words.\n *\n * @example\n * ```ts\n * camelToWords('helloWorld'); // → 'hello World'\n * camelToWords('HelloWorld'); // → 'Hello World'\n * camelToWords('userIDNumber'); // → 'user ID Number'\n * ```\n */\nexport const camelToWords = (input: string) => input.replace(/([a-z0-9])([A-Z])/g, '$1 $2');\n","/**\n * Splits a string into an array of filtered from redundant spaces words.\n *\n * @param input - The input string to be split.\n *\n * @returns An array of words from the input string.\n */\nexport const splitStringIntoWords = (input: string): string[] => {\n if (input.length === 0) {\n return [];\n }\n\n return input.split(' ').filter(Boolean);\n};\n","import { isNil } from '~/guards';\n\n/**\n * Checks whether the provided value is considered \"empty\".\n *\n * A value is considered empty if it is:\n * - `null`\n * - `undefined`\n * - `''`\n *\n * @param value - The value to check.\n *\n * @returns `true` if the value is empty; otherwise, `false`.\n */\nexport const isNilOrEmptyString = (value: unknown): value is null | undefined =>\n value === '' || isNil(value);\n","/**\n * Splits a file name into its base name and extension.\n *\n * Special cases:\n * - Files without a dot return `[fileName, \"\"]`\n * - Hidden files like `.gitignore` return `[\".gitignore\", \"\"]`\n * - Names ending with a trailing dot (e.g., `\"file.\"`) return `[\"file.\", \"\"]`\n * - Multi-dot names (e.g., `\"archive.tar.gz\"`) split on the last dot\n *\n * @param fileName - The full file name to parse.\n *\n * @returns A tuple where:\n * - index 0 is the base name\n * - index 1 is the file extension (lowercased), or an empty string if none exists\n */\nexport const parseFileName = (fileName: string) => {\n const lastDotIndex = fileName.lastIndexOf('.');\n\n // No dot or leading dot with no extension (e.g., \".gitignore\")\n if (lastDotIndex <= 0 || lastDotIndex === fileName.length - 1) {\n return [fileName, ''];\n }\n\n return [fileName.slice(0, lastDotIndex), fileName.slice(lastDotIndex + 1).toLowerCase()];\n};\n","/**\n * Finds all zero-based indices where a given single character occurs in a string.\n *\n * The string is scanned once from start to end and each matching character position is collected.\n *\n * ⚠️ Character comparison is performed at the UTF-16 code unit level\n * (`String.charCodeAt`), not by Unicode grapheme clusters.\n *\n * @param input - The string to scan.\n * @param targetChar - A single character to search for.\n *\n * @returns An array of zero-based indices for each occurrence of `targetChar`.\n * Returns an empty array if no matches are found.\n */\nexport const findCharIndices = (input: string, targetChar: string): number[] => {\n if (input.length === 0) {\n return [];\n }\n\n const targetCode = targetChar.charCodeAt(0);\n const indices: number[] = [];\n\n for (let i = 0; i < input.length; i++) {\n if (input.charCodeAt(i) === targetCode) {\n indices.push(i);\n }\n }\n\n return indices;\n};\n","import type { Nullable } from '~/types';\n\n/**\n * Context information for the currently processed character during string iteration.\n *\n * Provides the character index and access to adjacent characters in the input string.\n * All character values are UTF-16 code units.\n */\ninterface CharContext {\n /**\n * Zero-based index of the current character within the input string.\n */\n charIndex: number;\n /**\n * The previous character in the string, or `null` if the current character is the first one.\n */\n prevChar: Nullable<string>;\n /**\n * The next character in the string, or `null` if the current character is the last one.\n */\n nextChar: Nullable<string>;\n}\n\n/**\n * Callback invoked for each processed character during string iteration.\n */\ntype CharHandler = (char: string, context: CharContext) => void;\n\n/**\n * Predicate used to conditionally skip characters during string iteration.\n *\n * Returning `true` indicates that the current character should be skipped.\n */\ntype CharPredicate = (char: string, context: CharContext) => boolean;\n\n/**\n * Iterates over each character of a string and invokes a callback for each one.\n *\n * Iteration is performed over UTF-16 code units (not Unicode grapheme clusters).\n * Characters may be conditionally skipped using an optional predicate.\n *\n * @param input - The string to iterate over.\n * @param onChar - Invoked for each character that is not skipped.\n * @param shouldSkipChar - Optional predicate; returning `true` skips the character.\n */\nexport const forEachChar = (\n input: string,\n onChar: CharHandler,\n shouldSkipChar?: CharPredicate,\n): void => {\n if (input.length === 0) {\n return;\n }\n\n const length = input.length;\n\n for (let charIndex = 0; charIndex < length; charIndex++) {\n const char = input[charIndex];\n\n const context: CharContext = {\n charIndex,\n prevChar: charIndex > 0 ? input[charIndex - 1] : null,\n nextChar: charIndex < length - 1 ? input[charIndex + 1] : null,\n };\n\n if (shouldSkipChar?.(char, context)) {\n continue;\n }\n\n onChar(char, context);\n }\n};\n","import { splitStringIntoWords } from './split-string-into-words';\n\n/**\n * Returns the uppercase initials of the words in a string.\n *\n * The first character of each word is extracted, concatenated, and uppercased.\n *\n * @param input - The input string.\n * @param maxWords - Maximum number of words to include when generating initials.\n * Defaults to `Infinity`.\n *\n * @returns A string containing the uppercase initials of the selected words.\n */\nexport const getWordsInitials = (input: string, maxWords = Infinity): string => {\n if (input.length === 0) {\n return '';\n }\n\n return splitStringIntoWords(input)\n .slice(0, maxWords)\n .map(word => word[0])\n .join('')\n .toUpperCase();\n};\n","/**\n * Splits a string into parts, transforms each part, then joins them back together.\n *\n * Common use cases:\n *\n * - Transforming selector groups:\n *\n * ```ts\n * splitMapJoin(\".a, .b\", \",\", part => `.scope ${part}`);\n * // \".scope .a, .scope .b\"\n * ```\n *\n * - Normalizing spacing:\n *\n * ```ts\n * splitMapJoin(\"a , b ,c\", \",\", part => part);\n * // \"a,b,c\"\n * ```\n *\n * - Custom join formatting:\n *\n * ```ts\n * splitMapJoin(\"a,b,c\", \",\", part => part.toUpperCase(), \".\");\n * // \"A.B.C\"\n * ```\n *\n * @param input - The raw input string to process.\n * @param separator - The delimiter used to split the input (e.g. `\",\"`, `\" \"`).\n * @param mapFn - Function applied to each trimmed part.\n * @param joinWith - Optional join separator (defaults to the same value as `separator`).\n *\n * @returns The transformed and re-joined string.\n */\nexport const splitMapJoin = (\n input: string,\n separator: string,\n mapFn: (part: string, index: number) => string,\n joinWith: string = separator,\n): string =>\n input\n .split(separator)\n .map((part, index) => mapFn(part.trim(), index))\n .join(joinWith);\n","import type { KeysWithArrayValues, KeysWithNonArrayValues } from '~/types';\nimport type { HoneyTreeFlatNode } from '~/tree';\n\n/**\n * Flattens a hierarchical tree into a single preorder array.\n *\n * Each node in the returned list is stripped of its nested children property\n * (`childrenKey`) and enriched with hierarchy metadata:\n *\n * - `parentId` — identifier of the parent node (`undefined` for roots)\n * - `depthLevel` — nesting depth starting at `0`\n * - `childCount` — number of direct child nodes\n *\n * The flattening order is **preorder**, meaning parents always appear before\n * their descendants. This representation is especially useful for rendering\n * tree-based UIs such as TreeSelect components, nested menus, and folder pickers.\n *\n * @template OriginItem - Original node shape of the hierarchical structure.\n *\n * @param items - Root-level nodes to flatten. If undefined, an empty array is returned.\n * @param nodeIdKey - Key that uniquely identifies each node.\n * @param childrenKey - Key containing the nested child node array.\n *\n * @param flatTree - Internal accumulator used during recursion.\n * @param parentId - Parent identifier for the current recursion level.\n * @param depthLevel - Current depth level, where `0` represents the root.\n *\n * @returns A flat preorder list of tree nodes with hierarchy metadata attached,\n * excluding the original children property.\n *\n * @example\n * ```ts\n * const tree = [\n * {\n * id: 1,\n * name: 'Root',\n * children: [{ id: 2, name: 'Child', children: [] }],\n * },\n * ];\n *\n * const flatTree = flattenTree(tree, 'id', 'children');\n *\n * // [\n * // { id: 1, name: 'Root', parentId: undefined, depthLevel: 0, childCount: 1 },\n * // { id: 2, name: 'Child', parentId: 1, depthLevel: 1, childCount: 0 }\n * // ]\n * ```\n */\nexport const flattenTree = <OriginItem extends object>(\n items: OriginItem[] | undefined,\n nodeIdKey: KeysWithNonArrayValues<OriginItem>,\n childrenKey: KeysWithArrayValues<OriginItem>,\n ///\n flatTree: HoneyTreeFlatNode<OriginItem, typeof childrenKey>[] = [],\n parentId: OriginItem[KeysWithNonArrayValues<OriginItem>] | undefined = undefined,\n depthLevel = 0,\n): HoneyTreeFlatNode<OriginItem, typeof childrenKey>[] => {\n items?.forEach(item => {\n const { [childrenKey]: _, ...nodeData } = item;\n\n const children = item[childrenKey];\n const hasChildrenArray = Array.isArray(children);\n\n flatTree.push({\n ...nodeData,\n parentId,\n depthLevel,\n childCount: hasChildrenArray ? children.length : 0,\n });\n\n if (hasChildrenArray) {\n const parentId = item[nodeIdKey];\n\n flattenTree(children, nodeIdKey, childrenKey, flatTree, parentId, depthLevel + 1);\n }\n });\n\n return flatTree;\n};\n","import type { KeysWithNonArrayValues } from '~/types';\nimport type { HoneyTreeFlatNode } from '~/tree';\n\n/**\n * Returns the direct children of a given parent node from a flattened tree.\n *\n * This helper filters a flat tree representation (`HoneyTreeFlatNode`) and\n * selects only nodes whose `parentId` matches the provided identifier.\n *\n * ⚠️ Only direct children are returned - descendants at deeper levels are not included.\n *\n * An optional predicate may be provided to further narrow the result set\n * (e.g. filtering by depth, type, or custom node flags).\n *\n * @template OriginItem - Original node shape of the hierarchical structure.\n * @template ChildrenKey - Key of the removed nested children property.\n *\n * @param flatTree - Flat preorder list of tree nodes containing hierarchy metadata.\n * @param parentId - Identifier of the parent node whose direct children should be returned.\n * @param predicate - Optional additional filter applied to each matched child node.\n *\n * @returns An array of nodes that are direct children of the specified parent.\n *\n * @example\n * ```ts\n * const children = getTreeChildren(flatTree, 1);\n *\n * // Returns all nodes where parentId === 1\n * ```\n *\n * @example\n * ```ts\n * const shallowChildren = getTreeChildren(\n * flatTree,\n * 1,\n * node => node.depthLevel <= 2,\n * );\n *\n * // Returns only children of node 1 that satisfy the predicate.\n * ```\n */\nexport const getTreeChildren = <OriginItem extends object, ChildrenKey extends string>(\n flatTree: HoneyTreeFlatNode<OriginItem, ChildrenKey>[],\n parentId: OriginItem[KeysWithNonArrayValues<OriginItem>],\n predicate?: (node: HoneyTreeFlatNode<OriginItem, ChildrenKey>) => boolean,\n) => flatTree.filter(node => node.parentId === parentId && (!predicate || predicate(node)));\n","import type { KeysWithNonArrayValues, KeysWithStringValues } from '~/types';\nimport type { HoneyTreeFlatNode } from '~/tree';\nimport { assert, isNull, isUndefined } from '~/guards';\nimport { splitStringIntoWords } from '~/string';\n\n/**\n * Performs a context-aware search over a flattened tree.\n *\n * Matching is applied to the provided string field (`nodeValueKey`) using\n * **case-insensitive, word-prefix comparison**:\n *\n * - The query is split into words\n * - Each query word must match the start of at least one word in the node value\n *\n * Unlike a simple filter, this function preserves hierarchical context:\n *\n * - When a nested node matches, all of its ancestor nodes are included, so the\n * result remains navigable.\n * - When a root node matches, its full descendant subtree is included so the\n * hierarchy stays intact.\n *\n * This makes the utility ideal for searchable tree-based UIs such as\n * TreeSelect components, folder pickers, nested menus, and grouped lists.\n *\n * @template OriginItem - Original node shape of the hierarchical structure.\n * @template ChildrenKey - Key of the removed nested children property.\n *\n * @param flatTree - Flat preorder list of tree nodes containing hierarchy metadata.\n * @param nodeIdKey - Key that uniquely identifies each node.\n * @param nodeValueKey - Key containing the searchable string value (e.g. `\"name\"`).\n * @param searchQuery - User input query. Split into words and matched by prefix.\n *\n * @returns A filtered flat list containing:\n * - all matching nodes\n * - their ancestor chain (for nested matches)\n * - full descendant subtrees (for root-level matches)\n *\n * @example\n * ```ts\n * const results = searchTree(flatTree, 'id', 'label', 'kit che');\n *\n * // Matches nodes where words start with \"kit\" and \"che\"\n * // (e.g. \"Kitchen Chair\"), including their parents.\n * ```\n *\n * @example\n * ```ts\n * // If a deep child matches, ancestors are included:\n * //\n * // Root\n * // └─ Category\n * // └─ Item ← matches\n * //\n * // Result includes: Root, Category, Item\n * ```\n */\nexport const searchTree = <OriginItem extends object, ChildrenKey extends string>(\n flatTree: HoneyTreeFlatNode<OriginItem, ChildrenKey>[],\n nodeIdKey: KeysWithNonArrayValues<OriginItem>,\n nodeValueKey: KeysWithStringValues<OriginItem>,\n searchQuery: string,\n) => {\n const searchWords = splitStringIntoWords(searchQuery.toLowerCase());\n if (!searchWords.length) {\n return flatTree;\n }\n\n const nodeIdToIndexMap = flatTree.reduce<Record<string, number>>((result, node, nodeIndex) => {\n // Map node id → index for fast ancestor lookup.\n result[node[nodeIdKey as never]] = nodeIndex;\n\n return result;\n }, {});\n\n return flatTree.reduce<HoneyTreeFlatNode<OriginItem, ChildrenKey>[]>((matchedNodes, node) => {\n const nodeValue = node[nodeValueKey as never];\n // If the item value is null, undefined or empty string\n if (!nodeValue) {\n return matchedNodes;\n }\n\n if (\n matchedNodes.some(matchedNode => matchedNode[nodeIdKey as never] === node[nodeIdKey as never])\n ) {\n return matchedNodes;\n }\n\n const nodeValueWords = splitStringIntoWords((nodeValue as string).toLowerCase());\n\n const isNodeMatched = searchWords.every(searchWord =>\n nodeValueWords.some(word => word.startsWith(searchWord)),\n );\n\n if (isNodeMatched) {\n if (isUndefined(node.parentId)) {\n matchedNodes.push(node);\n\n const insertNestedItems = (targetNode: HoneyTreeFlatNode<OriginItem, ChildrenKey>) => {\n if (!targetNode.childCount) {\n return;\n }\n\n flatTree.forEach(node => {\n if (node.parentId === targetNode[nodeIdKey as never]) {\n matchedNodes.push(node);\n\n insertNestedItems(node);\n }\n });\n };\n\n insertNestedItems(node);\n } else {\n const insertParentNodes = (targetNode: HoneyTreeFlatNode<OriginItem, ChildrenKey>) => {\n const parentNodeIndex = nodeIdToIndexMap[targetNode.parentId as never];\n const parentNode = flatTree[parentNodeIndex];\n\n if (!isUndefined(parentNode.parentId)) {\n insertParentNodes(parentNode);\n }\n\n const prevNodeParentId = matchedNodes.length\n ? matchedNodes[matchedNodes.length - 1].parentId\n : null;\n\n const shouldInsertParentNode =\n isNull(prevNodeParentId) || prevNodeParentId !== targetNode.parentId;\n\n if (shouldInsertParentNode) {\n assert(parentNode, '[@react-hive/honey-utils]: Parent node was not found.');\n\n matchedNodes.push(parentNode);\n }\n };\n\n insertParentNodes(node);\n\n matchedNodes.push(node);\n }\n }\n\n return matchedNodes;\n }, []);\n};\n","import { assert } from '~/guards';\n\n/**\n * Represents a hexadecimal CSS color value.\n *\n * This type enforces a leading `#`, but does not validate length\n * at the type level (e.g. `#RGB`, `#RRGGBB`, `#RRGGBBAA`).\n *\n * Valid runtime examples:\n * - `#fff`\n * - `#ffffff`\n * - `#ffffffff`\n */\nexport type HexColor = `#${string}`;\n\n/**\n * Adds an alpha channel to a 3- or 6-digit HEX color.\n *\n * Accepts `#RGB`, `#RRGGBB`, `RGB`, or `RRGGBB` formats\n * and returns a normalized 8-digit HEX color in `#RRGGBBAA` format.\n *\n * The alpha value is converted to a two-digit hexadecimal\n * representation using `Math.round(alpha * 255)`.\n *\n * @param input - Base HEX color (3 or 6 hex digits, with or without `#`).\n * @param alpha - Opacity value between `0` (transparent) and `1` (opaque).\n *\n * @throws {Error}\n * - If `alpha` is outside the `[0, 1]` range.\n * - If `hex` is not a valid 3- or 6-digit hexadecimal color.\n *\n * @returns A normalized 8-digit HEX color in `#RRGGBBAA` format.\n *\n * @example\n * ```ts\n * hexWithAlpha('#ff0000', 0.5) // '#FF000080'\n * hexWithAlpha('0f0', 1) // '#00FF00FF'\n * ```\n */\nexport const hexWithAlpha = (input: string, alpha: number): HexColor => {\n assert(\n alpha >= 0 && alpha <= 1,\n `[@react-hive/honey-utils]: Alpha \"${alpha}\" must be a number between 0 and 1.`,\n );\n\n const hexRegex = /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;\n\n const match = input.match(hexRegex);\n assert(match, `[@react-hive/honey-utils]: Invalid hex format: ${input}`);\n\n const cleanHex = match[1];\n\n // Expand 3-character hex to 6-character hex if necessary\n const fullHex =\n cleanHex.length === 3\n ? cleanHex[0] + cleanHex[0] + cleanHex[1] + cleanHex[1] + cleanHex[2] + cleanHex[2]\n : cleanHex;\n\n // Convert to 8-character hex with alpha\n const alphaHex = Math.round(alpha * 255)\n .toString(16)\n .toUpperCase()\n .padStart(2, '0');\n\n return `#${fullHex + alphaHex}`;\n};\n"],"names":["cloneBlob","blob","Blob","type","getElementOffsetRect","element","DOMRect","offsetLeft","offsetTop","clientWidth","clientHeight","isAnchorHtmlElement","tagName","isContentEditableHtmlElement","getAttribute","FOCUSABLE_HTML_TAGS","isHtmlElementFocusable","style","window","getComputedStyle","visibility","display","disabled","tabIndex","includes","href","getFocusableHtmlElements","container","Array","from","querySelectorAll","filter","moveFocusWithinContainer","direction","wrap","getNextIndex","activeElement","document","scope","parentElement","focusableElements","length","currentIndex","indexOf","nextIndex","focus","assert","condition","message","Error","isNull","value","isNil","isDefined","isUndefined","undefined","isNumber","isBool","isObject","isEmptyObject","Object","keys","isDate","Date","isBlob","isError","isValidDate","isNaN","getTime","isRegExp","RegExp","isMap","Map","isSet","Set","isSymbol","isFiniteNumber","isFinite","isInteger","Number","isDecimal","isArray","isEmptyArray","compact","array","Boolean","unique","chunk","size","Math","ceil","_","index","slice","intersection","arrays","first","rest","item","every","difference","exclude","pipe","fns","arg","reduce","prev","fn","compose","reduceRight","noop","isFunction","not","args","once","result","called","apply","this","isPromise","then","runSequential","async","results","i","push","runParallel","Promise","all","map","filterSequential","predicate","filterParallel","someAsync","everyAsync","reduceAsync","initialValue","accumulator","findAsync","delay","delayMs","resolve","setTimeout","timeout","promise","timeoutMs","errorMessage","race","reject","retry","task","maxAttempts","backoff","onRetry","lastError","attempt","e","delayTime","isString","downloadFile","file","fileName","target","link","createElement","objectUrl","URL","createObjectURL","download","body","appendChild","click","remove","revokeObjectURL","hasXOverflow","scrollWidth","getXOverflowWidth","max","hasYOverflow","scrollHeight","getYOverflowHeight","calculateCenterOffset","overflowSize","containerSize","elementOffset","elementSize","targetOffset","min","centerElementInContainer","containerElement","elementToCenter","axis","translateX","translateY","transform","parse2DMatrix","matrixMatch","getPropertyValue","match","scaleX","scaleY","skewX","skewY","split","parseFloat","isLocalStorageReadable","localStorage","getItem","getLocalStorageCapabilities","readable","writable","key","setItem","removeItem","isFile","File","fileListToFiles","fileList","files","blobToFile","traverseFileSystemDirectory","directoryEntry","skipFiles","skipFilesSet","entries","directoryReader","createReader","readAll","readEntries","restEntries","readFileSystemDirectoryEntries","entry","isDirectory","has","name","flat","readFilesFromDataTransfer","dataTransfer","traverseOptions","items","tasks","itemIndex","webkitGetAsEntry","getAsFile","invokeIfFunction","input","resolveBoundedDelta","delta","candidate","applyInertiaStep","velocityPxMs","deltaTimeMs","friction","minVelocityPxMs","emaAlpha","abs","nextValue","pureVelocityPxMs","exp","nextVelocityPxMs","generateEphemeralId","floor","performance","now","toString","random","getDOMRectIntersectionRatio","sourceRect","targetRect","right","left","bottom","top","width","height","resolveAxisDelta","allowFallback","invert","sign","deltaX","deltaY","calculateEuclideanDistance","startX","startY","endX","endY","hypot","calculateMovingSpeed","distance","elapsedTime","calculatePercentage","percentage","hashString","hash","charCodeAt","definedProps","obj","toKebabCase","replace","toLowerCase","camelToDashCase","firstChar","charAt","restOfString","letter","camelToWords","splitStringIntoWords","isNilOrEmptyString","parseFileName","lastDotIndex","lastIndexOf","findCharIndices","targetChar","targetCode","indices","forEachChar","onChar","shouldSkipChar","charIndex","char","context","prevChar","nextChar","getWordsInitials","maxWords","Infinity","word","join","toUpperCase","splitMapJoin","separator","mapFn","joinWith","part","trim","flattenTree","nodeIdKey","childrenKey","flatTree","parentId","depthLevel","forEach","nodeData","children","hasChildrenArray","childCount","getTreeChildren","node","searchTree","nodeValueKey","searchQuery","searchWords","nodeIdToIndexMap","nodeIndex","matchedNodes","nodeValue","some","matchedNode","nodeValueWords","searchWord","startsWith","insertNestedItems","targetNode","insertParentNodes","parentNodeIndex","parentNode","prevNodeParentId","hexWithAlpha","alpha","cleanHex","round","padStart"],"ignoreList":[],"sourceRoot":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-hive/honey-utils",
3
- "version": "3.24.0",
3
+ "version": "3.25.0",
4
4
  "description": "A lightweight TypeScript utility library providing a collection of helper functions for common programming tasks",
5
5
  "keywords": [
6
6
  "utils",