@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
TypeScript
/*!
* ====================================================
* 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 };