## @explita/utils

A lightweight and versatile collection of TypeScript utility functions and React hooks designed for everyday development needs. Streamline your Node.js, React, and Next.js projects with a powerful set of well-organized helpers for strings, arrays, dates, objects, and more.

#### Features

- **String Manipulation**: Comprehensive set of helpers for formatting, casing, and slugifying.
- **Object Transformation**: Deep merge, flatten, and unflatten objects with type safety.
- **Date Utilities**: Extensive helpers for formatting, shifting, and comparing dates.
- **Array Utilities**: Chunking, duplication finding, and shuffling.
- **React Hooks**: Premium hooks like `useList`, `useLocalStorage` (with cross-tab sync), and more.
- **File Export**: Save data as CSV, XML, or JSON directly from the browser.
- **Type Safety**: Built with TypeScript from the ground up.

#### Installation

```bash
# npm
npm install @explita/utils

# pnpm
pnpm add @explita/utils

# yarn
yarn add @explita/utils
```

---

#

### 📚 API Reference

#### 🧵 String Utilities

`import { ... } from "@explita/utils"`

| Function           | Description                           | Example                                            |
| :----------------- | :------------------------------------ | :------------------------------------------------- |
| `addOrdinal`       | Appends ordinal suffix to number.     | `addOrdinal(1) // "1st"`                           |
| `buildQueryString` | Builds query string from object.      | `buildQueryString({a:1}) // "a=1"`                 |
| `capitalize`       | Capitalizes the first letter.         | `capitalize("hello") // "Hello"`                   |
| `chunkSplit`       | Splits string with separator.         | `chunkSplit("123456", 3, "-") // "123-456"`        |
| `convertFileSize`  | Formats bytes to human-readable.      | `convertFileSize(1024) // "1.0 KB"`                |
| `formatCurrency`   | Formats number as currency.           | `formatCurrency(1000, "$") // "$1,000.00"`         |
| `greeting`         | Returns greeting based on time.       | `greeting("John") // "Good morning John"`          |
| `hexToRgb`         | Converts Hex color to RGB.            | `hexToRgb("#FF0000") // "rgb(255, 0, 0)"`          |
| `isEmpty`          | Checks if value is empty/null.        | `isEmpty("") // true`                              |
| `isValidEmail`     | Validates email format.               | `isValidEmail("test@test.com") // true`            |
| `isValidPassword`  | Validates password strength.          | `isValidPassword("Pass123!") // true`              |
| `isValidPhone`     | Validates phone number.               | `isValidPhone("+1234567") // true`                 |
| `nl2br`            | Replaces `\n` with `<br>`.            | `nl2br("hi\nthere") // "hi<br>there"`              |
| `parseQueryString` | Parses URL query to object.           | `parseQueryString("?a=1") // {a: "1"}`             |
| `randomColor`      | Generates random color (hex/rgb/hsl). | `randomColor("hex")`                               |
| `rgbToHex`         | Converts RGB color to Hex.            | `rgbToHex(255, 0, 0) // "#FF0000"`                 |
| `slugify`          | Creates a URL-friendly slug.          | `slugify("Hello World!") // "hello-world"`         |
| `toCamelCase`      | Converts string to camelCase.         | `toCamelCase("hello-world") // "helloWorld"`       |
| `toKebabCase`      | Converts string to kebab-case.        | `toKebabCase("Hello World") // "hello-world"`      |
| `toRomanNumeral`   | Converts number to Roman.             | `toRomanNumeral(4) // "IV"`                        |
| `toSentenceCase`   | Converts string to Sentence case.     | `toSentenceCase("hello world") // "Hello world"`   |
| `toSnakeCase`      | Converts string to snake_case.        | `toSnakeCase("Hello World") // "hello_world"`      |
| `toTitleCase`      | Converts string to Title Case.        | `toTitleCase("hello_world") // "Hello World"`      |
| `truncateEmail`    | Hides parts of an email.              | `truncateEmail("john@doe.com") // "jo***@doe.com"` |
| `uniqueString`     | Generates a random string.            | `uniqueString(10) // "aB3dE5gH1j"`                 |

---

#

#### 📦 Object Utilities

`import { ... } from "@explita/utils"`

| Function          | Description                        | Example                                    |
| :---------------- | :--------------------------------- | :----------------------------------------- |
| `deepMerge`       | Deeply merges two objects.         | `deepMerge({a:1}, {b:2}) // {a:1, b:2}`    |
| `flattenObject`   | Flattens a nested object.          | `flattenObject({a:{b:1}}) // {"a.b": 1}`   |
| `isObject`        | Checks if value is a plain object. | `isObject({}) // true`                     |
| `jsonify`         | Handles BigInts & Dates for JSON.  | `jsonify(objWithBigInt)`                   |
| `omitFromObject`  | Removes specific keys.             | `omitFromObject(obj, ['password'])`        |
| `pickFromObject`  | Picks specific keys.               | `pickFromObject(obj, ['id', 'name'])`      |
| `prependKeys`     | Adds prefix to all object keys.    | `prependKeys({a:1}, "p_") // {p_a: 1}`     |
| `unflattenObject` | Restores a flattened object.       | `unflattenObject({"a.b": 1}) // {a:{b:1}}` |

---

#

#### 📅 Date Utilities

`import { ... } from "@explita/utils"`

| Function           | Description                       | Example                                |
| :----------------- | :-------------------------------- | :------------------------------------- |
| `formatDate`       | Advanced date formatting.         | `formatDate(date, "YYYY-MM-DD")`       |
| `formatTime`       | Advanced time formatting.         | `formatTime(date, "hh:mm A")`          |
| `formatDateTime`   | Combined date & time format.      | `formatDateTime(date)`                 |
| `timeAgo`          | Returns relative time string.     | `timeAgo(pastDate) // "2 hours ago"`   |
| `dayOfYear`        | Gets day number of the year.      | `dayOfYear(date) // 1-366`             |
| `daysBetween`      | Calculates diff in days.          | `daysBetween(date1, date2)`            |
| `daysInMonth`      | Gets number of days in month.     | `daysInMonth(2024, 1) // 29`           |
| `daysSince`        | Days elapsed since date.          | `daysSince(pastDate)`                  |
| `daysUntil`        | Days remaining until date.        | `daysUntil(futureDate)`                |
| `endOfMonth`       | Returns last moment of month.     | `endOfMonth(date)`                     |
| `extractDate`      | Gets `YYYY-MM-DD` string.         | `extractDate(date)`                    |
| `extractDOB`       | Parses DOB from identifier.       | `extractDOB("ID_NUMBER")`              |
| `firstDayOfMonth`  | Returns first day of month Date.  | `firstDayOfMonth(date)`                |
| `getDayName`       | Gets full day name.               | `getDayName(date) // "Monday"`         |
| `getMonthName`     | Gets full month name.             | `getMonthName(date) // "January"`      |
| `isFuture`         | Checks if date is in future.      | `isFuture(date)`                       |
| `isPast`           | Checks if date is in past.        | `isPast(date)`                         |
| `isToday`          | Checks if date is today.          | `isToday(date)`                        |
| `isValidDate`      | Robust valid date check.          | `isValidDate("2024-01-01") // true`    |
| `isWeekday`        | Checks if day is Mon-Fri.         | `isWeekday(date)`                      |
| `isWeekend`        | Checks if day is Sat-Sun.         | `isWeekend(date)`                      |
| `isWithinInterval` | Checks if date is in range.       | `isWithinInterval(date, {start, end})` |
| `isYesterday`      | Checks if date was yesterday.     | `isYesterday(date)`                    |
| `lastDayOfMonth`   | Returns last day of month Date.   | `lastDayOfMonth(date)`                 |
| `normalizeDate`    | Sets time to 00:00:00.            | `normalizeDate(date)`                  |
| `shiftDays`        | Adds/subtracts days.              | `shiftDays(date, 5)`                   |
| `shiftMonths`      | Adds/subtracts months.            | `shiftMonths(date, 1)`                 |
| `shiftYears`       | Adds/subtracts years.             | `shiftYears(date, 1)`                  |
| `startOfDay`       | Returns first moment of day.      | `startOfDay(date)`                     |
| `startOfMonth`     | Returns first moment of month.    | `startOfMonth(date)`                   |
| `toDate`           | Robust conversion to Date object. | `toDate("2024-01-01")`                 |
| `weekOfYear`       | Gets week number of the year.     | `weekOfYear(date)`                     |

---

#

#### 🔢 Number Utilities

`import { ... } from "@explita/utils"`

| Function     | Description                 | Example                       |
| :----------- | :-------------------------- | :---------------------------- |
| `isNumeric`  | Robust numeric check.       | `isNumeric("123.45") // true` |
| `percentage` | Calculates percentage.      | `percentage(50, 200) // 25`   |
| `random`     | Generates a random integer. | `random(1, 100)`              |

---

#

#### 🧪 Array Utilities

`import { ... } from "@explita/utils"`

| Function         | Description                | Example                                 |
| :--------------- | :------------------------- | :-------------------------------------- |
| `chunk`          | Splits array into sizes.   | `chunk([1,2,3,4], 2) // [[1,2], [3,4]]` |
| `findDuplicates` | Finds duplicates by key.   | `findDuplicates(data, 'email')`         |
| `flattenArray`   | Flattens a nested array.   | `flattenArray([[1], [2]]) // [1, 2]`    |
| `groupByKey`     | Groups objects by key.     | `groupByKey(users, 'role')`             |
| `shuffle`        | Randomizes array order.    | `shuffle([1, 2, 3])`                    |
| `unique`         | Removes duplicates.        | `unique([1, 2, 2, 3]) // [1, 2, 3]`     |
| `uniqueByKey`    | Removes duplicates by key. | `uniqueByKey(data, 'id')`               |

---

#

#### ⚡ Misc Utilities

`import { ... } from "@explita/utils"`

| Function   | Description                     | Example                       |
| :--------- | :------------------------------ | :---------------------------- |
| `debounce` | Limits function execution rate. | `debounce(fn, 500)`           |
| `delay`    | Promisified timeout.            | `await delay(1000)`           |
| `logger`   | Conditional console logging.    | `logger.info("data")`         |
| `retry`    | Retries a failing function.     | `await retry(fn, {times: 3})` |
| `throttle` | Limits execution frequency.     | `throttle(fn, 500)`           |
| `tryCatch` | Clean async error handling.     | `tryCatch(fetch(url))`        |

---

#

#### 📡 Axios Utilities

`import { ... } from "@explita/utils/axios"`

| Function   | Description                                                                                                                | Example                                  |
| :--------- | :------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------- |
| `tryAxios` | Optimized tryCatch for Axios. Supports generic error schemas and includes `kind`, `meta`, and `original` error properties. | `tryAxios<T, ErrorSchema>(api.get(url))` |

**Error Properties:**

- `kind`: Categorizes the error as `"network"`, `"logic"`, or `"unknown"`.
- `meta`: Contains an error snapshot including `name`, `message`, and `stack`.
- `original`: The raw `AxiosError` for deep inspection.
- **Dynamic Data**: Automatically spreads the response body (e.g., `message`, `errors`) into the error object for direct access.

---

#

#### 💾 File Utilities (Browser Only)

`import { ... } from "@explita/utils/file"`

| Function         | Description           | Example                          |
| :--------------- | :-------------------- | :------------------------------- |
| `saveCSVToFile`  | Exports data as CSV.  | `saveCSVToFile(data, "users")`   |
| `saveJSONToFile` | Exports data as JSON. | `saveJSONToFile(data, "config")` |
| `saveXMLToFile`  | Exports data as XML.  | `saveXMLToFile(data, "report")`  |

---

#

#### 🛡️ Zod Validation

`import { ... } from "@explita/utils/zod"`

| Function              | Description                                                                 | Example                       |
| :-------------------- | :-------------------------------------------------------------------------- | :---------------------------- |
| `validateForm`        | Validates FormData or objects using Zod schemas with clean error responses. | `validateForm(data, schema)`  |
| `mapZodIssues`        | Converts Zod issues into a flat `Record<string, string>`.                   | `mapZodIssues(error.issues)`  |
| `createDefaultValues` | Generates initial values based on a Zod schema.                             | `createDefaultValues(schema)` |
| `isZodIssue`          | Type guard for Zod issues.                                                  | `isZodIssue(error)`           |

---

#

#### ⚛️ React Hooks

`import { ... } from "@explita/utils/react"`

| Hook              | Description                                                          |
| :---------------- | :------------------------------------------------------------------- |
| `stripTags`       | Utility to strip HTML tags from string or ReactNode.                 |
| `useDisclosure`   | Open/Close/Toggle management for modals and drawers.                 |
| `useList`         | Advanced state management for arrays (append, filter, remove, etc.). |
| `useLocalStorage` | Persistent state with auto-serialization and cross-tab sync.         |
| `useLocation`     | Geolocation manager with permission handling.                        |
| `useNetwork`      | Current online status and connection details (rtt, downlink).        |
| `useWindowScroll` | Reactive scroll positions and programmatic scroll helpers.           |
| `useWindowSize`   | Responsive window dimensions and device type booleans.               |

#

**Example Usage:**

```tsx
import { useList, useLocalStorage } from "@explita/utils/react";

function App() {
  const [items, { append, remove }] = useList(["Task 1"]);
  const [theme, setTheme] = useLocalStorage("theme", "dark");

  return (
    <div className={theme}>
      <button onClick={() => append("New Task")}>Add</button>
      {items.map((it, i) => (
        <div onClick={() => remove(i)}>{it}</div>
      ))}
    </div>
  );
}
```

---

#

## 💖 Support the Mission

@explita/utils is built to provide a versatile collection of helpers that streamline everyday development. If these utilities or hooks have saved you time or improved your code quality, please consider supporting the project to ensure its continued growth and maintenance!

<p align="left">
  <a href="https://github.com/sponsors/explita">
    <img src="https://img.shields.io/badge/Sponsor_on_GitHub-EA4AAA?style=for-the-badge&logo=github-sponsors&logoColor=white" />
  </a>
  <a href="https://ko-fi.com/explita">
    <img src="https://img.shields.io/badge/Buy_Me_A_Coffee-FF5E5B?style=for-the-badge&logo=ko-fi&logoColor=white" />
  </a>
</p>

### 🚀 Ways to Contribute

- **Give us a ⭐**: It helps others discover the project.
- **Join the Discussion**: Report [bugs](https://github.com/explita/utils/issues) or suggest new [features](https://github.com/explita/utils/discussions).
- **Spread the Word**: Share your experience with @explita/utils on social media.

### 🙏 Our Amazing Supporters

*A huge thank you to everyone helping us build better dev tools!*

[![Contributors](https://contrib.rocks/image?repo=explita/utils)](https://github.com/explita/utils/graphs/contributors)

#

### 📄 License

MIT © [Explita](https://github.com/explita)
