/*! * ======================================================================== * @rzl-zone/utils-js * ------------------------------------------------------------------------ * Version: `3.15.0` * Author: `Rizalvin Dwiky ` * Repository: `https://github.com/rzl-zone/rzl-zone/tree/main/packages/utils-js` * ======================================================================== */ import { D as NumberRangeUnion } from "../index-Cr6qFcbC.cjs"; type CopyMethod = "clipboard" | "fallback" | "manual"; type CopyStatus = "success" | "error"; type CopyResult = { /** --------------------------------------------------------- * * ***Final operation status.*** * ---------------------------------------------------------- * * --- * Usually `"success"` when copy succeeds, otherwise `"error"`. */ status: CopyStatus; /** --------------------------------------------------------- * * ***Indicates whether the operation succeeded.*** * ---------------------------------------------------------- * * Usually `true` on successful copy operations. */ success: boolean; /** --------------------------------------------------------- * * ***Copy mechanism that was used.*** * ---------------------------------------------------------- * * - **Possible values:** * - `"clipboard"`. * - `"fallback"`. * - `"manual"`. */ method: CopyMethod; /** * * ***Optional error object captured during execution.*** */ error?: unknown; /** --------------------------------------------------------- * * ***Optional failure or fallback reason.*** * ---------------------------------------------------------- * * - **Possible values:** * - `"no-browser"`. * - `"no-clipboard"`. * - `"clipboard-error"`. * - `"timeout"`. * - `"fallback-failed"`. */ reason?: "no-browser" | "no-clipboard" | "clipboard-error" | "timeout" | "fallback-failed"; /** * * ***Total number of attempts performed.*** */ attempts: number; /** * * ***Total execution duration in milliseconds.*** */ duration: number; /** * * ***Unix timestamp of execution completion.*** */ timestamp: number; }; /** ---------------------------------------------------------------------- * * ***Type: `CopyOptions`.*** * ----------------------------------------------------------------------- * **Configuration options for the `copyText` utility.** * * --- * - **Behavior:** * - Controls retry attempts and timeout handling. * - Enables optional debug logging. * - All properties are optional. */ type CopyOptions = { /** ----------------------------------------------------------------------- * * ***Enables internal debug logging.*** * ------------------------------------------------------------------------ * * @default false */ debug?: boolean; /** ----------------------------------------------------------------------- * * ***Number of retry attempts before fallback.*** * ------------------------------------------------------------------------ * * @default 1 */ retries?: number; /** ----------------------------------------------------------------------- * * ***Timeout duration (in milliseconds) for each Clipboard API attempt.*** * ------------------------------------------------------------------------ * * @default 2000 */ timeout?: number; }; /** ---------------------------------------------------------------------- * * ***Utility: `copyText`.*** * ----------------------------------------------------------------------- * **Copies text to the user's clipboard with robust fallback handling.** * * --- * - **Behavior:** * - Attempts to use the modern * ***`navigator.clipboard.writeText`*** Clipboard API. * - Automatically retries clipboard operations when configured. * - Falls back to legacy * ***`document.execCommand("copy")`*** * if the Clipboard API is unavailable or fails. * - As a last resort, programmatically selects the text * to allow manual copying by the user. * - Detects non-browser environments and safely exits * without accessing browser-only APIs. * - Returns detailed operation metadata including method, * duration, attempts, and failure reason. * - Does **not throw** on copy failure; * instead returns a structured * ***{@link CopyResult | `CopyResult`}*** object. * * --- * @param {string} text * The text content to copy to the clipboard. * * @param {CopyOptions} [options={}] * Optional configuration object. * * @param {boolean} [options.debug=false] * Enables internal debug logging. * * @param {number} [options.retries=1] * Number of additional retry attempts * after the initial Clipboard API attempt. * * @param {number} [options.timeout=2000] * Timeout duration (in milliseconds) * for each Clipboard API attempt. * * --- * @returns {Promise} * A promise resolving to a * ***{@link CopyResult | `CopyResult`}*** object containing: * - `status` ➔ `"success"` or `"error"`. * - `success` ➔ Indicates whether the operation succeeded. * - `method` ➔ Copy mechanism used * (`"clipboard"`, `"fallback"`, or `"manual"`). * - `reason` ➔ Optional failure or fallback reason. * - `error` ➔ Optional thrown error object. * - `attempts` ➔ Total number of attempts performed. * - `duration` ➔ Execution duration in milliseconds. * - `timestamp` ➔ Unix timestamp of execution. * * --- * @remarks * - The Clipboard API requires a secure context * (`HTTPS` or `localhost`). * - Some browsers or mobile environments may restrict * clipboard access without direct user interaction. * - Clipboard operations may fail due to browser permission * policies or missing user interaction. * - Manual selection mode is only triggered when all * programmatic copy strategies fail. * - In server-side environments, * the utility returns `"no-browser"` * without attempting DOM access. * * --- * @example * ```ts * const result = await copyText("Hello world"); * * if (result.success) { * console.log(`Copied using ${result.method}`); * } else { * console.error(result.reason); * } * ``` * * --- * @example * ```ts * await copyText("Debug mode", { * debug: true, * retries: 2 * }); * ``` */ declare function copyText(text: string, options?: CopyOptions): Promise; /** ---------------------------------------------------------------------- * * ***Utility: `findDuplicates`.*** * ----------------------------------------------------------------------- * **Finds duplicate values in an array by deep equality comparison.** * * --- * - **Behavior:** * - Uses ***`isEqual` utility function*** to compare elements * (handles objects, arrays, dates, NaN, etc.). * - Returns a new array containing only the *first occurrences* of duplicated values. * - Does **not mutate** the original array. * - Throws ***{@link TypeError | `TypeError`}*** if input is not an array. * * --- * @template T Type of elements in the input array. * * --- * @param {T[]} values - The array to check for duplicates. * * --- * @throws **{@link TypeError | `TypeError`}** if the provided `values` argument is not an array. * * --- * @returns {T[]} An array of the duplicate values found in the input, * preserving order of their first duplicate appearance. * * --- * @example * findDuplicates([1, 2, 2, 3, 4, 4]); * // ➔ [2, 4] * findDuplicates(["apple", "banana", "apple", "orange"]); * // ➔ ["apple"] * findDuplicates([{ a: 1 }, { a: 1 }, { a: 2 }]); * // ➔ [{ a: 1 }] * findDuplicates([NaN, NaN, 1]); * // ➔ [NaN] * findDuplicates([true, false, true]); * // ➔ [true] * findDuplicates([1, 2, 3]); * // ➔ [] */ declare const findDuplicates: (values: T[]) => T[]; /** ------------------------------------------------------------------------------- * * ***Utility: `omitKeys`.*** * -------------------------------------------------------------------------------- * **This function creates a shallow copy of the given object omitting the * specified keys.** * * --- * - **Behavior:** * - It will return a new object without mutating the original. * - It also validates that ***`keysToOmit`*** does not contain duplicate keys. * * --- * - **Internally:** * - It uses ***`isEqual`*** to check for duplicates in * the ***`keysToOmit`*** array. * * --- * @template I The type of the input object. * @template K The keys to omit from the object. * * --- * @param {I} object - The source object to omit keys from. * @param {K[]} keysToOmit - An array of keys to exclude from the returned object. * * --- * @throws **{@link TypeError | `TypeError`}** if `keysToOmit` is not an array. * @throws **{@link Error | `Error`}** if duplicate keys are found in `keysToOmit`. * * --- * @returns {Omit} A new object without the specified keys. * * --- * @example * omitKeys({ a: 1, b: 2, c: 3 }, ["b", "c"]); * // ➔ { a: 1 } * omitKeys({ name: "John", age: 30 }, ["age"]); * // ➔ { name: "John" } * omitKeys({ a: 1, b: 2 }, []); * // ➔ { a: 1, b: 2 } (no changes) */ declare const omitKeys: , K extends keyof I>(object: I, keysToOmit: K[]) => Omit; type IndexArray = NumberRangeUnion<0, 30>; type DotPath = T extends Array ? DotPath : T extends object ? { [K in keyof T & string]: `${Prev}${Prev extends "" ? "" : "."}${K}` | DotPath }[keyof T & string] : never; /** ------------------------------------------------------ * * ***Utility: `omitKeysDeep`.*** * ------------------------------------------------------- * **Recursively omits properties from an object using dot notation paths.** * * --- * - **Behavior:** * - Removes resulting empty objects (`{}`) and arrays (`[]`), cascading upwards * to remove empty parents until root if needed. * --- * - **Be careful:** * - If after omission an object or array becomes empty, it will be removed entirely * including all the way up to the root if necessary, resulting in `{}`. * --- * - **Note:** * - For array indices, TypeScript autocomplete only suggests `0`–`30` * (to prevent editor lag on large unions). * However, higher indices are still fully supported at runtime — you can * manually type `"arr.99.key"` and it will work the same. * * --- * @template I - Type of the input object. * * --- * @param {I} object * The object to process, should be a plain nested object or array structure. * @param {DotPath[]} keysToOmit * An array of string paths in dot notation indicating the properties to remove, paths * can include numeric indices to target array elements, e.g. `"arr.0.x"` to * remove `x` from the first object inside the `arr` array. * * --- * @throws **{@link TypeError | `TypeError`}** if `keysToOmit` is not an array. * @throws **{@link Error | `Error`}** if `keysToOmit` contains duplicate paths. * * --- * @returns {Partial} * A new deeply cloned object with the specified keys omitted, with resulting * empty objects or arrays fully removed (even if it collapses to `{}`). * * --- * @example * omitKeysDeep({ arr: [{ a: 1 }] }, ["arr.0.a"]); * // ➔ {} (array becomes empty and removed) * omitKeysDeep({ a: { b: { c: 1 }, d: 2 }, e: 3 }, ["a.b.c"]); * // ➔ { a: { d: 2 }, e: 3 } * omitKeysDeep({ a: [{ b: 1 }, { c: 2 }] }, ["a.0.b"]); * // ➔ { a: [{ c: 2 }] } * omitKeysDeep({ a: [{ b: 1 }] }, ["a.0.b"]); * // ➔ {} (array becomes empty and removed) * omitKeysDeep({ complex: [{ deep: [{ x: 1, y: 2 }] }] }, ["complex.0.deep.0.x"]); * // ➔ { complex: [{ deep: [{ y: 2 }] }] } * omitKeysDeep({ complex: [{ deep: [{ x: 1 }] }] }, ["complex.0.deep.0.x"]); * // ➔ {} (deep chain emptied and collapsed) * omitKeysDeep({ data: [[{ foo: 1, bar: 2 }]] }, ["data.0.0.foo"]); * // ➔ { data: [[{ bar: 2 }]] } * omitKeysDeep({ data: [[{ foo: 1 }]] }, ["data.0.0.foo"]); * // ➔ {} (nested arrays emptied completely) * omitKeysDeep({ x: [{ y: [{ z: 1 }, { w: 2 }] }] }, ["x.0.y.0.z"]); * // ➔ { x: [{ y: [{ w: 2 }] }] } * omitKeysDeep({ x: [{ y: [{ z: 1 }] }] }, ["x.0.y.0.z"]); * // ➔ {} (entire nested arrays removed) * omitKeysDeep({ p: { q: { r: 5 } }, s: 6 }, ["p.q.r"]); * // ➔ { s: 6 } (`p` removed because it becomes empty) * omitKeysDeep({ arr: [{ a: 1, b: 2 }, { c: 3 }] }, ["arr.0.a"]); * // ➔ { arr: [{ b: 2 }, { c: 3 }] } * omitKeysDeep({ root: [{ sub: [{ leaf: 10 }] }] }, ["root.0.sub.0.leaf"]); * // ➔ {} (deep nested arrays emptied to root) * omitKeysDeep({ meta: { tags: ["x", "y"], count: 2 } }, ["meta.count"]); * // ➔ { meta: { tags: ["x", "y"] } } * omitKeysDeep({ arr: [[{ a: 1 }, { b: 2 }]] }, ["arr.0.0.a"]); * // ➔ { arr: [[{ b: 2 }]] } * omitKeysDeep({ arr: [[{ a: 1 }]] }, ["arr.0.0.a"]); * // ➔ {} (double nested emptied) * omitKeysDeep({ nested: [{ list: [{ id: 1, val: 2 }] }] }, ["nested.0.list.0.val"]); * // ➔ { nested: [{ list: [{ id: 1 }] }] } * omitKeysDeep({ nested: [{ list: [{ id: 1 }] }] }, ["nested.0.list.0.id"]); * // ➔ {} (full collapse to empty) * omitKeysDeep({ mixed: { a: [1, 2, 3], b: { c: 4 } } }, ["mixed.b.c"]); * // ➔ { mixed: { a: [1, 2, 3] } } */ declare const omitKeysDeep: >(object: I, keysToOmit: DotPath[]) => Partial; export { copyText, findDuplicates, omitKeys, omitKeysDeep };