UNPKG

@rzl-zone/utils-js

Version:

A modern, lightweight set of JavaScript utility functions with TypeScript support for everyday development, crafted to enhance code readability and maintainability.

714 lines (703 loc) 28.5 kB
/*! * ==================================================== * Rzl Utils-JS. * ---------------------------------------------------- * Version: 3.11.0. * Author: Rizalvin Dwiky. * Repository: https://github.com/rzl-zone/utils-js. * ==================================================== */ import { Config } from 'tailwindcss'; import { ClassNameValue as ClassNameValue$1, ConfigExtension as ConfigExtension$1 } from 'tailwind-merge-v3'; import { ClassNameValue, ConfigExtension } from 'tailwind-merge-v4'; import { Stringify } from '@rzl-zone/ts-types-plus'; /** ---------------------------------------------------------- * * ***Type-Utility: `ClassValue`.*** * ---------------------------------------------------------- * **Represents a single valid value that can be converted to a CSS class string.** * @description * - Supports the following types: * - `string` → literal class names (non-empty only) * - `number | bigint` → numeric class names * - `boolean` → only `true` is considered in objects/arrays * - `null | undefined` → ignored * - `ClassObject` → objects where **keys with truthy values** are included * - `ClassValues` → arrays recursively flattened * - Used internally by ***`cx` utility function*** to process mixed input values. * @example * ```ts * const val1: ClassValue = "button"; // ➔ string * const val2: ClassValue = 0; // ➔ number * const val3: ClassValue = ["a", { b: true }]; // ➔ array with object * const val4: ClassValue = { d: true, e: false }; // ➔ object * const val5: ClassValue = new String("foo"); // ➔ boxed string * const val6: ClassValue = new Number("123"); // ➔ boxed number * const val7: ClassValue = new Boolean("true"); // ➔ boxed boolean * ``` */ type ClassValue = ClassValues | ClassObject | string | number | bigint | null | boolean | undefined; /** ---------------------------------------------------------- * * ***Type-Utility: `ClassObject`.*** * ---------------------------------------------------------- * **Represents an object whose keys with truthy values are included in the final class string.** * @example * ```ts * const obj: ClassObject = { "text-red": true, "hidden": false }; * // ➔ "text-red" when processed by cx * ``` */ type ClassObject = Record<string, any>; /** ---------------------------------------------------------- * * ***Type-Utility: `ClassValues`.*** * ---------------------------------------------------------- * **Represents an array of {@link ClassValue | `ClassValue's`}, potentially nested.** * @example * ```ts * const arr: ClassValues = [ * "a", * 1, * ["b", { c: true, d: false }], * { e: 2 } * ]; * ``` */ type ClassValues = ClassValue[]; /** ---------------------------------------------------------- * * ***Utility: `cx`.*** * ---------------------------------------------------------- * **Merge multiple class values into a single, space-separated string suitable for CSS usage.** * @description * - Supports **nested combinations** of arrays and objects, recursively. * - **Falsy values** are skipped: * - `false`, `null`, `undefined`, empty strings `""` are ignored anywhere. * - Numbers `0` are ignored inside nested arrays/objects. * - **Boxed primitives** are correctly unwrapped to their primitive value. * - **Inherited object keys** are included in the final class string. * - Optimized for **CSS class merging** where conditional inclusion is common. * @param {ClassValues} values * A list of mixed class values, which can include: * - **Strings** → literal class names. * - **Numbers** → numeric class names. * - **BigInt** → numeric class names larger than JS safe integer limit. * - **Arrays** → recursively flattened, can contain nested arrays or objects. * - **Objects** → include keys whose values are truthy. Inherited keys are also included. * - **Boxed primitives** (`new String()`, `new Number()`, `new Boolean()`) → automatically unwrapped. * - **Falsy values** (`false`, `null`, `undefined`, `""`, `0`) are ignored according to original behavior. * @returns {string} * A single space-separated string containing all valid class names. * @example * ```ts * // Basic string merge * cx("btn", "btn-primary"); * // ➔ "btn btn-primary" * * // Mixed arrays and objects * cx("a", ["b", { c: true, d: false }], { e: 1, f: 0 }, null, 2); * // ➔ "a b c e 2" * * // Empty and falsy values are ignored * cx("", null, undefined, false, 0); * // ➔ "" * * // Nested arrays with objects * cx(["a", ["b", { c: true, d: false }]]); * // ➔ "a b c" * * // Boxed primitives are unwrapped * cx(new String("foo"), new Number(42), new Boolean(true), new Number(0), new Boolean(false)); * // ➔ "foo 42 true" * * // Inherited keys from objects are included * const proto = { inherited: true }; * const obj = Object.create(proto); * obj.own = true; * cx(obj); * // ➔ "own inherited" * ``` */ declare function cx(...values: ClassValues): string; /** ------------------------------------------------------------- * * ***Default `cnV3` utility (Tailwind v3).*** * ------------------------------------------------------------- * **Combines class-name values and then deduplicates/resolves * conflicts using {@link twMergeDefaultV3 | `twMergeDefaultV3`} * with **Tailwind v3 default config only**.** * - ✅ **Use this when:** * - Your project uses **Tailwind v3**. * - You need a simple `cn` that works out of the box without a custom config. * - ⚡ **Need custom rules?** * - Create a project-wide helper using * {@link twMergeDefaultV3 | `twMergeDefaultV3`} + * {@link customCnV3 | `customCnV3`} (see Example 2). * @param {ClassValues} classes - Class values (`string`, `array`, `object`, `etc`). * @returns {string} Merged Tailwind class string. * @example * #### Example 1: ✅ Default usage (Tailwind v3). * ```ts * cnV3("p-2", "p-4"); * // ➔ "p-4" * * cnV3("text-red-500", { "text-blue-500": true }); * // ➔ "text-blue-500" * * cnV3(["m-2", ["m-4"]], "m-8"); * // ➔ "m-8" * ``` * #### Example 2: ⚡ Custom project-wide usage with Tailwind config. * ```ts * import tailwindConfig from "../tailwind.config"; * import { twMergeDefaultV3, customCnV3, type ClassValues } from "@rzl-zone/utils-js/tailwind"; * * const cnApp = (...classes: ClassValues) => { * return customCnV3( * twMergeDefaultV3({ * config: tailwindConfig, * extend: { * classGroups: { * "text-shadow": [ * "text-shadow", * "text-shadow-sm", * "text-shadow-md", * ], * }, * }, * }), * // ...other options classes, * ); * }; * * cnApp("p-2 p-4"); // ➔ "p-4" * cnApp("shadow-sm shadow-md"); // ➔ "shadow-md" * cnApp("text-base text-xxs"); // ➔ "text-xxs" (resolved from config) * ``` */ declare const cnV3: (...classes: ClassValues) => string; /** ------------------------------------------------------------- * * ***Default `cnV4` utility (Tailwind v4).*** * ------------------------------------------------------------- * **Combines class-name values and then deduplicates/resolves * conflicts using {@link twMergeDefaultV4 | `twMergeDefaultV4`} * with **Tailwind v4 default config only**.** * - ✅ **Use this when:** * - Your project uses **Tailwind v4**. * - You need a simple `cn` that works out of the box without a custom config. * - ⚡ **Need custom rules?** * - Create a project-wide helper using * {@link twMergeDefaultV4 | `twMergeDefaultV4`} + * {@link customCnV4 | `customCnV4`} (see Example 2). * @param {ClassValues} classes - Class values (`string`, `array`, `object`, `etc`). * @returns {string} Merged Tailwind class string. * @example * #### Example 1: ✅ Default usage (Tailwind v4). * ```ts * cnV4("p-2", "p-4"); * // ➔ "p-4" * * cnV4("text-red-500", { "text-blue-500": true }); * // ➔ "text-blue-500" * * cnV4(["m-2", ["m-4"]], "m-8"); * // ➔ "m-8" * ``` * #### Example 2: ⚡ Custom project-wide usage with Tailwind config. * ```ts * import tailwindConfig from "../tailwind.config"; * import { twMergeDefaultV4, customCnV4, type ClassValues } from "@rzl-zone/utils-js/tailwind"; * * const cnApp = (...classes: ClassValues) => { * return customCnV4( * twMergeDefaultV4({ * config: tailwindConfig, * extend: { * classGroups: { * "text-shadow": [ * "text-shadow", * "text-shadow-sm", * "text-shadow-md", * ], * }, * }, * }), * // ...other options classes, * ); * }; * * cnApp("p-2 p-4"); // ➔ "p-4" * cnApp("shadow-sm shadow-md"); // ➔ "shadow-md" * cnApp("text-base text-xxs"); // ➔ "text-xxs" (resolved from config) * ``` */ declare const cnV4: (...classes: ClassValues) => string; /** Tailwind Merge config extension type */ type TwMergeConfigExt$1 = ConfigExtension<string, string>; /** * ***Extra options for customized Tailwind class merge.*** */ type OptionsConfigMergeTwCn$1 = { /** ---------------------------------------------------------- * * ***Optional Tailwind CSS configuration object.*** * ---------------------------------------------------------- * - **Pass your project’s `tailwind.config.ts` if you want to:** * - Respect custom theme values (`colors`, `fontSize`, `spacing`, `etc`.) * - Enable/disable `corePlugins` * - Register `plugins` * - Extend class groups (e.g., `text-shadow`) * - **If omitted, the **default Tailwind config** is used.** * @example * ```ts * import tailwindConfig from "../tailwind.config"; * import { twMergeDefaultV4 } from "@rzl-zone/utils-js/tailwind"; * * const myCustomTwCls = twMergeDefaultV4({ * config: tailwindConfig, * }); * * myCustomTwCls("text-primary text-secondary"); * // => "text-secondary" (resolved from your theme config) * ``` */ config?: TailwindConfig; /** ---------------------------------------------------------- * * ***Prefix added to Tailwind-generated classes.*** * ---------------------------------------------------------- * - **Tailwind v3**: * - Use {@link twMergeDefaultV3 | **`twMergeDefaultV3`**} instead. * - Reference: * [**`Tailwind v3 using prefix docs`**](https://v3.tailwindcss.com/docs/configuration#prefix). * * - **Tailwind v4**: * - Configure in your CSS import, e.g. `@import "tailwindcss" prefix(tw);` * - The prefix appears like a variant at the start of the class, e.g. `tw:flex`, * `tw:bg-red-500`, `tw:hover:bg-red-600`. * - Reference: * [**`Tailwind v4 using prefix docs`**](https://tailwindcss.com/docs/upgrade-guide#using-a-prefix). * * - **ℹ️ Notes**: * - Tailwind v3: * - Use {@link twMergeDefaultV3 | **`twMergeDefaultV3`**} instead. * - Tailwind v4: prefer identifier (e.g. `tw`) without `-`. * - Fallback order: * 1. `prefix` option * 2. `config.prefix` (if defined) * 3. `undefined` * * @example * - Tailwind version 4 (in CSS entry only): * - CSS files: * ```css * `@import "tailwindcss" prefix(tw);` * ``` * - Your custom TwMerge file: * ```ts * import { twMergeDefaultV4 } from "@rzl-zone/utils-js/tailwind"; * * const twMergeV3 = twMergeDefaultV4({ * prefix: "tw", * // ... other config * }); * ``` * - Tailwind version 4 (with `tailwind.config.{js,ts,mjs,...etc}`): * - Reference: * [**`Tailwind v4 using @config docs`**](https://tailwindcss.com/docs/functions-and-directives#config-directive). * - CSS files: * ```css * `@import "tailwindcss";` * `@config "./tailwind.config.ts";` * ``` * - Config files: * ```ts * import type { Config } from "tailwindcss"; * * const config: Config = { * prefix: 'tw-', * // ... other config * }; * * export default config; * ``` * - Your custom TwMerge file: * ```ts * import config from "../tailwind.config"; * import { twMergeDefaultV4 } from "@rzl-zone/utils-js/tailwind"; * * const twMergeV4 = twMergeDefaultV4({ config }); * // now without passing `prefix` options, will use automatic from config. * ``` */ prefix?: string; }; /** * ***Options type for Tailwind Merge v4 wrapper.*** */ type OptionsMergeTwClsV4 = Omit<TwMergeConfigExt$1, "prefix"> & OptionsConfigMergeTwCn$1; /** * ***Tailwind Merge function Version 4 signature (same as twMerge).*** */ type TwMergeDefaultFnV4 = (...classLists: ClassNameValue[]) => string; type TailwindConfig = Config; /** Tailwind Merge config extension type */ type TwMergeConfigExt = ConfigExtension$1<string, string>; /** * ***Extra options for customized Tailwind class merge.*** */ type OptionsConfigMergeTwCn = { /** ---------------------------------------------------------- * * ***Optional Tailwind CSS configuration object.*** * ---------------------------------------------------------- * - **Pass your project’s `tailwind.config.ts` if you want to:** * - Respect custom theme values (`colors`, `fontSize`, `spacing`, `etc`.) * - Enable/disable `corePlugins` * - Register `plugins` * - Extend class groups (e.g., `text-shadow`) * - **If omitted, the **default Tailwind config** is used.** * @example * ```ts * import tailwindConfig from "../tailwind.config"; * import { twMergeDefaultV3 } from "@rzl-zone/utils-js/tailwind"; * * const myCustomTwCls = twMergeDefaultV3({ * config: tailwindConfig, * }); * * myCustomTwCls("text-primary text-secondary"); * // => "text-secondary" (resolved from your theme config) * ``` */ config?: TailwindConfig; /** ---------------------------------------------------------- * * ***Prefix added to Tailwind-generated classes.*** * ---------------------------------------------------------- * - **Tailwind v3**: * - Configure in `tailwind.config.js`, e.g. `prefix: 'tw-'`. * - Variants first; negative utilities: `-mt-8` ➔ `-tw-mt-8`. * - Reference: * [**`Tailwind v3 using prefix docs`**](https://v3.tailwindcss.com/docs/configuration#prefix). * - **Tailwind v4**: * - Use {@link twMergeDefaultV4 | **`twMergeDefaultV4`**} instead. * - Reference: * [**`Tailwind v4 using prefix docs`**](https://tailwindcss.com/docs/upgrade-guide#using-a-prefix). * - **ℹ️ Notes**: * - Tailwind v3: use hyphenated prefix (`tw-`). * - Fallback order: * 1. `prefix` option * 2. `config.prefix` (if defined) * 3. `undefined` * - Tailwind v4: * - Use {@link twMergeDefaultV4 | **`twMergeDefaultV4`**} instead. * @example * - Tailwind version 3 (`tailwind.config.ts`): * ```ts * import type { Config } from "tailwindcss"; * * const config: Config = { * prefix: 'tw-', * // ... other config * }; * * export default config; * ``` */ prefix?: string; }; /** * ***Options type for Tailwind Merge v3 wrapper.*** */ type OptionsMergeTwClsV3 = Omit<TwMergeConfigExt, "prefix"> & OptionsConfigMergeTwCn; /** * ***Tailwind Merge function Version 3 signature (same as twMerge).*** */ type TwMergeDefaultFnV3 = (...classLists: ClassNameValue$1[]) => string; /** ------------------------------------------------------------- * * ***Factory utility for building a custom `cn` helper (Tailwind `v3`).*** * ------------------------------------------------------------- * **Wraps internally function to combines class-name values and applies the provided * Tailwind merge function (from {@link twMergeDefaultV3 | `twMergeDefaultV3`}).** * - 🔑 **When to use it?** * - Your project uses **Tailwind v3**. * - You extend Tailwind merge rules (`classGroups`, `tailwind.config`). * - You need multiple `cn*` variants across apps/packages. * @param {TwMergeDefaultFnV3} customTwMergeV3 - Merge function created via {@link twMergeDefaultV3 | `twMergeDefaultV3`}. * @param {ClassValues} classes - Class values (`string`, `array`, `object`, `etc`). * @returns {string} Merged Tailwind class string. * @example * ```ts * import tailwindConfig from "../tailwind.config"; * import { twMergeDefaultV3, customCnV3, type ClassValues } from "@rzl-zone/utils-js/tailwind"; * * // 1. Create a custom merge function * const myCustomTwMerge = twMergeDefaultV3({ * config: tailwindConfig, * extend: { * classGroups: { * "text-shadow": ["text-shadow", "text-shadow-sm", "text-shadow-md"], * }, * }, * }); * * // 2. Build your helper using `customCnV3` * export const cnApp = (...classes: ClassValues) => { * return customCnV3(myCustomTwMerge, ...classes); * }; * // ✅ Usage * cnApp("p-2", "p-4"); // ➔ "p-4" * cnApp("shadow-sm shadow-md"); // ➔ "shadow-md" * cnApp("text-base text-xxs"); // ➔ "text-xxs" (resolved from config) * ``` */ declare const customCnV3: (customTwMergeV3: TwMergeDefaultFnV3, ...classes: ClassValues) => string; /** ------------------------------------------------------------- * * ***Factory utility for building a custom `cn` helper (Tailwind `v4`).*** * ------------------------------------------------------------- * **Wraps internally function to combines class-name values and applies the provided * Tailwind merge function (from {@link twMergeDefaultV4 | `twMergeDefaultV4`}).** * - 🔑 **When to use it?** * - Your project uses **Tailwind v4**. * - You extend Tailwind merge rules (`classGroups`, `tailwind.config`). * - You need multiple `cn*` variants across apps/packages. * @param {TwMergeDefaultFnV4} customTwMergeV4 - Merge function created via {@link twMergeDefaultV4 | `twMergeDefaultV4`}. * @param {ClassValues} classes - Class values (`string`, `array`, `object`, `etc`). * @returns {string} Merged Tailwind class string. * @example * ```ts * import tailwindConfig from "../tailwind.config"; * import { twMergeDefaultV4, customCnV4, type ClassValues } from "@rzl-zone/utils-js/tailwind"; * * // 1. Create a custom merge function * const myCustomTwMerge = twMergeDefaultV4({ * config: tailwindConfig, * extend: { * classGroups: { * "text-shadow": ["text-shadow", "text-shadow-sm", "text-shadow-md"], * }, * }, * }); * * // 2. Build your helper using `customCnV4` * export const cnApp = (...classes: ClassValues) => { * return customCnV4(myCustomTwMerge, ...classes); * }; * * // ✅ Usage * cnApp("p-2", "p-4"); // ➔ "p-4" * cnApp("shadow-sm shadow-md"); // ➔ "shadow-md" * cnApp("text-base text-xxs"); // ➔ "text-xxs" (resolved from config) * ``` */ declare const customCnV4: (customTwMergeV4: TwMergeDefaultFnV4, ...classes: ClassValues) => string; /** ---------------------------------------------------------- * * ***Utility: `shouldForwardProp`.*** * ---------------------------------------------------------- * **Creates a helper for styled-components `shouldForwardProp`.** * * @description * 1. Returns a **predicate function** that determines whether a given prop * should be forwarded to the DOM. * 2. Useful for filtering out internal props (e.g., `$size`, `$active`) * so they don't become invalid HTML attributes. * * - **Behavior:** * - Accepts a strict tuple of **string keys** to exclude from forwarding. * - Every key is validated as a **non-empty string** at runtime. * - Throws a `TypeError` if: * - `props` is not an array, or * - any item is not a non-empty string. * - Automatically coerces the tested prop name to string for matching. * * @template CustomProps * The component props type to validate against. * * @param {readonly Stringify<keyof CustomProps>[]} * props * The list of prop names (keys of `CustomProps`) to exclude from forwarding. * * @returns {(propName: keyof CustomProps | ({} & string)) => boolean} * A function that receives a prop name and returns: * - `true` ➔ the prop **will** be forwarded to the DOM. * - `false` ➔ the prop **will not** be forwarded. * * @throws **{@link TypeError | `TypeError`}** * when: * - `props` is not an array, or * - any item is not a non-empty string. * * @example * // Basic usage * type Props = { $size: string; color: string; visible: boolean }; * const filter = shouldForwardProp<Props>(["$size"]); * * filter("$size"); // ➔ false (blocked). * filter("color"); // ➔ true (forwarded). * filter("visible"); // ➔ true (forwarded). * * @example * // With styled-components * type CustomProps = { $internal: boolean; public: string; another: boolean }; * * styled.div.withConfig({ * shouldForwardProp: shouldForwardProp<CustomProps>(["$internal"]) * }); */ declare const shouldForwardProp: <CustomProps extends Record<string, unknown>>(props: readonly Stringify<keyof CustomProps>[]) => ((propName: keyof CustomProps | ({} & string)) => boolean); /** ------------------------------------------------------------- * * ***Customized Tailwind class merger Version 3 with extended rules.*** * ------------------------------------------------------------- * **Wraps ***`extendTailwindMerge` from tailwind-merge-v3*** with Tailwind’s default * config (_*`getDefaultConfig()` from tailwind-merge-v3*_) to create a **project-ready `twMerge`**.** * - 🔑 **When to use it?** * - Your project uses **Tailwind v3**. * - Extend **class groups** (e.g. add `text-shadow`). * - Respect your own **`tailwind.config.ts`** (colors, spacing, fontSize, etc). * - Override or fine-tune **merge behavior**. * - Create a **project-wide `cn` helper** that replaces raw `twMerge`. * @param {OptionsMergeTwClsV3} [options={}] * ***Merge options:*** * - `config` – Your Tailwind config (from `tailwind.config.ts`). * - `prefix` - Utility prefix (e.g. `tw-` or `tw`). * - `extend` – Extra merge rules (classGroups, theme, etc). * - `override` – Fully replace rules. * - `cacheSize` – Parsed class cache size. * - `experimentalParseClassName` – Custom classname parser. * @returns {TwMergeDefaultFnV3} * Customized Tailwind class merge function version 3 (same signature as `twMerge`). * @example * #### Example 1: ***Default behavior (same as tailwind-merge).*** * ```ts * import { twMergeDefaultV3 } from "@rzl-zone/utils-js/tailwind"; * * const twMerge = twMergeDefaultV3(); * twMerge("p-2 p-4"); * // ➔ "p-4" * ``` * #### Example 2: ***Extend class groups.*** * ```ts * import { twMergeDefaultV3 } from "@rzl-zone/utils-js/tailwind"; * * const twMerge2 = twMergeDefaultV3({ * extend: { * classGroups: { * shadow: ["shadow-soft", "shadow-hard"], * }, * }, * }); * twMerge2("shadow-soft shadow-hard"); * // ➔ "shadow-hard" * ``` * #### Example 3: ***Respect your Tailwind config.*** * ```ts * import config from "../tailwind.config"; * import { twMergeDefaultV3 } from "@rzl-zone/utils-js/tailwind"; * * const twMerge3 = twMergeDefaultV3({ config }); * twMerge3("text-base text-xxs"); * // ➔ "text-xxs" (resolved from config) * ``` * #### Example 4: ***Project-wide helper (recommended).*** * ```ts * import configTwCss from "../tailwind.config"; * import { customCnV3, twMergeDefaultV3, type ClassValues } from "@rzl-zone/utils-js/tailwind"; * * const customTwMerge = twMergeDefaultV3({ * config: configTwCss, * extend: { * classGroups: { shadow: ["shadow-soft", "shadow-hard"] }, * }, * }); * * export const cnApp = (...classes: ClassValues) => { * return customCnV3(customTwMerge, ...classes); * }; * * // ✅ Usage * cnApp("p-2 p-4"); // ➔ "p-4" * cnApp("shadow-soft shadow-hard"); // ➔ "shadow-hard" * cnApp("text-base text-xxs"); // ➔ "text-xxs" (uses config) * * // ⚡ Difference with package-level `cn` * import { cnV3, cnV4 } from "@rzl-zone/utils-js/tailwind"; * * cnV3("text-base text-xxs"); * // or * cnV4("text-base text-xxs"); * // ➔ "text-base" (❌ doesn't know about your config) * * cnApp("text-base text-xxs"); * // ➔ "text-xxs" (✅ respects config) * ``` */ declare const twMergeDefaultV3: (options?: OptionsMergeTwClsV3) => TwMergeDefaultFnV3; /** ------------------------------------------------------------- * * ***Customized Tailwind class merger Version 4 with extended rules.*** * ------------------------------------------------------------- * **Wraps ***`extendTailwindMerge` from tailwind-merge-v4*** with Tailwind’s default * config (_*`getDefaultConfig()` from tailwind-merge-v4*_) to create a **project-ready `twMerge`**.** * - 🔑 **When to use it?** * - Your project uses **Tailwind v4**. * - Extend **class groups** (e.g. add `text-shadow`). * - Respect your own **`tailwind.config.ts`** (colors, spacing, fontSize, etc). * - Override or fine-tune **merge behavior**. * - Create a **project-wide `cn` helper** that replaces raw `twMerge`. * @param {OptionsMergeTwClsV4} [options={}] * ***Merge options:*** * - `config` – Your Tailwind config (from `tailwind.config.ts`). * - `prefix` - Utility prefix (e.g. `tw-` or `tw`). * - `extend` – Extra merge rules (classGroups, theme, etc). * - `override` – Fully replace rules. * - `cacheSize` – Parsed class cache size. * - `experimentalParseClassName` – Custom classname parser. * @returns {TwMergeDefaultFnV4} * Customized Tailwind class merge function version 4 (same signature as `twMerge`). * @example * #### Example 1: ***Default behavior (same as tailwind-merge).*** * ```ts * import { twMergeDefaultV4 } from "@rzl-zone/utils-js/tailwind"; * * const twMerge = twMergeDefaultV4(); * twMerge("p-2 p-4"); * // ➔ "p-4" * ``` * #### Example 2: ***Extend class groups.*** * ```ts * import { twMergeDefaultV4 } from "@rzl-zone/utils-js/tailwind"; * * const twMerge2 = twMergeDefaultV4({ * extend: { * classGroups: { * shadow: ["shadow-soft", "shadow-hard"], * }, * }, * }); * twMerge2("shadow-soft shadow-hard"); * // ➔ "shadow-hard" * ``` * #### Example 3: ***Respect your Tailwind config.*** * ```ts * import config from "../tailwind.config"; * import { twMergeDefaultV4 } from "@rzl-zone/utils-js/tailwind"; * * const twMerge3 = twMergeDefaultV4({ config }); * twMerge3("text-base text-xxs"); * // ➔ "text-xxs" (resolved from config) * ``` * #### Example 4: ***Project-wide helper (recommended).*** * ```ts * import configTwCss from "../tailwind.config"; * import { customCnV4, twMergeDefaultV4, type ClassValues } from "@rzl-zone/utils-js/tailwind"; * * const customTwMerge = twMergeDefaultV4({ * config: configTwCss, * extend: { * classGroups: { shadow: ["shadow-soft", "shadow-hard"] }, * }, * }); * * export const cnApp = (...classes: ClassValues) => { * return customCnV4(customTwMerge, ...classes); * }; * * // ✅ Usage * cnApp("p-2 p-4"); // ➔ "p-4" * cnApp("shadow-soft shadow-hard"); // ➔ "shadow-hard" * cnApp("text-base text-xxs"); // ➔ "text-xxs" (uses config) * * // ⚡ Difference with package-level `cn` * import { cnV3, cnV4 } from "@rzl-zone/utils-js/tailwind"; * * cnV3("text-base text-xxs"); * // or * cnV4("text-base text-xxs"); * // ➔ "text-base" (❌ doesn't know about your config) * * cnApp("text-base text-xxs"); * // ➔ "text-xxs" (✅ respects config) * ``` */ declare const twMergeDefaultV4: (options?: OptionsMergeTwClsV4) => TwMergeDefaultFnV4; export { type ClassObject, type ClassValue, type ClassValues, cnV3, cnV4, customCnV3, customCnV4, cx, shouldForwardProp, twMergeDefaultV3, twMergeDefaultV4 };