npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@apx-ui/toolkit

v1.0.14

Published

Universal Web Utility SDK for apx-ui (AppNA UX/UI) frontend applications

Readme

@apx-ui/toolkit

Apx Toolkit AppNA.io apx-ui apx-ui 220 test cases passed

A modern utility SDK for frontend web applications.
Includes regex-based validators, generic helpers, formatting utilities, date tools, magic constants, phone number formatting, scroll utilities, storage persister, and more.

Table of Contents


Getting Started

1. Installation

npm install @apx-ui/toolkit

or

yarn add @apx-ui/toolkit

Note: This package has zero external dependencies, making it lightweight and secure for production use.

2. Initialize Context (Recommended)

We strongly recommend initializing the library context at the start of your application. This provides a centralized configuration for all utilities and ensures consistent behavior across your app.

import { config } from '@apx-ui/toolkit';

// Initialize once at app startup
config({
    defaultLanguage: 'en',
    defaultCurrency: 'USD', 
    defaultTimezone: 'America/New_York',
    defaultRegion: 'US',
    persist: 'localStorage', // 'localStorage' | 'sessionStorage' | 'memory' | false
    debug: false
});

Context Benefits:

  • All formatters automatically use your configured settings
  • User preferences persist across sessions
  • Consistent formatting throughout your application
  • Easy to change settings globally

3. Basic Usage

import { 
    formatCurrencyI18N, 
    formatPhoneNumber, 
    isEmail, 
    scrollToTop 
} from '@apx-ui/toolkit';

// Currency formatting uses context settings
formatCurrencyI18N(1234.56); // Uses context currency & locale

// Phone number formatting
formatPhoneNumber('+12345678901', '+C (PPP)-EEE-SSSS'); // '+1 (234)-567-8901'

// Validation
isEmail('[email protected]'); // true

// Scroll utilities
scrollToTop({ duration: 1000, easing: 'easeInOut' });

4. Running Examples

The project includes comprehensive examples in the examples/ directory:

# Run specific examples
npx ts-node examples/basic-usage.ts
npx ts-node examples/phone-formatting-examples.ts
npx ts-node examples/scroll-utilities-demo.ts
npx ts-node examples/persister-demo.ts
npx ts-node examples/real-world-usage.ts

Available Examples:

  • basic-usage.ts - Core utilities overview
  • comprehensive-validators-demo.ts - All validation functions with examples
  • comprehensive-formatters-demo.ts - All formatting functions with examples
  • comprehensive-date-utilities-demo.ts - All date utilities with examples
  • comprehensive-generic-utilities-demo.ts - All generic helper functions with examples
  • credit-card-demo.ts - Credit card utilities with formatting, validation, and dummy generation
  • opening-hours-demo.ts - Opening hours formatting with multi-language support
  • phone-formatting-examples.ts - Phone number formatting patterns
  • phone-number-demo.ts - Phone number utility demo
  • scroll-utilities-demo.ts - Smooth scrolling utilities
  • persister-demo.ts - Storage with TTL functionality
  • real-world-usage.ts - Production-ready patterns
  • context-demo.ts - Context system usage
  • i18n-formatters-demo.ts - Internationalization
  • region-currency-demo.ts - Currency mapping
  • currency-utils-example.ts - Locale-based currency utilities
  • time-formatter-demo.ts - Time formatting
  • translations-demo.ts - Translation utilities

What's Included?

Validators (Regex-based)

isEmail(value: string): boolean
isPhone(value: string): boolean
isNumeric(value: string): boolean
isAlphanumeric(value: string): boolean
isValidURL(value: string): boolean
isStrongPassword(value: string): boolean
isCreditCard(value: string): boolean
isIPv4(value: string): boolean
isDate(value: string): boolean
isTime(value: string): boolean
isUUID(value: string): boolean
isPostalCode(value: string): boolean
isSSN(value: string): boolean
isCurrency(value: string): boolean
isHexColor(value: string): boolean
isDomain(value: string): boolean
isUsername(value: string): boolean
hasValidFileExtension(value: string): boolean
validateWithRegex(value: string, pattern: RegexPattern): boolean

// Validation with detailed results
validateEmail(email: string): ValidationResult
validatePhone(phone: string): ValidationResult
validateURL(url: string): ValidationResult
validatePassword(password: string): ValidationResult

Comprehensive Examples:

// Basic validation
isEmail('[email protected]'); // true
isPhone('+1234567890'); // true
isValidURL('https://example.com'); // true
isStrongPassword('MyPass123!'); // true

// Advanced validation
isCreditCard('4111111111111111'); // true (Visa)
isIPv4('192.168.1.1'); // true
isUUID('550e8400-e29b-41d4-a716-446655440000'); // true
isHexColor('#FF0000'); // true
isDomain('example.com'); // true

// Validation with detailed results
const emailResult = validateEmail('invalid-email');
console.log(emailResult); // { valid: false, error: 'Invalid email format' }

const passwordResult = validatePassword('weak');
console.log(passwordResult); // { valid: false, error: 'Password must be at least 8 characters long' }

// Form validation example
const formData = {
    email: '[email protected]',
    phone: '+1234567890',
    password: 'MyPass123!',
    website: 'https://example.com'
};

const validation = {
    email: validateEmail(formData.email),
    phone: validatePhone(formData.phone),
    password: validatePassword(formData.password),
    website: validateURL(formData.website)
};

// Check all validations
const isFormValid = Object.values(validation).every(result => result.valid);

Available Regex Patterns:

REGEX = {
    email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
    phone: /^(\+?\d{1,3})?\d{7,14}$/,
    numeric: /^\d+$/,
    alphanumeric: /^[a-zA-Z0-9]+$/,
    url: /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/i,
    strongPassword: /^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$/,
    creditCard: /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3[0-9]{13}|6(?:011|5[0-9]{2})[0-9]{12})$/,
    ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
    date: /^\d{4}-\d{2}-\d{2}$/,
    time: /^([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/,
    uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
    postalCode: /^\d{5}(-\d{4})?$/,
    ssn: /^\d{3}-\d{2}-\d{4}$/,
    currency: /^\$?\d+(\.\d{2})?$/,
    hexColor: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,
    domain: /^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/,
    username: /^[a-zA-Z0-9_]{3,20}$/,
    fileExtension: /\.(jpg|jpeg|png|gif|pdf|doc|docx|txt|zip|rar)$/i
}

Date & Time Utilities

formatDate(date: Date | string, format?: string): string  // Default: 'YYYY-MM-DD'
getTimeAgo(date: Date | string): string                   // e.g., '3 hours ago'
isSameDay(date1: Date, date2: Date): boolean
isSameMonth(date1: Date, date2: Date): boolean
isSameYear(date1: Date, date2: Date): boolean
toISOStringUTC(date: Date): string
startOfDay(date: Date): Date
endOfDay(date: Date): Date
startOfWeek(date: Date): Date
endOfWeek(date: Date): Date
startOfMonth(date: Date): Date
endOfMonth(date: Date): Date
addDays(date: Date, days: number): Date
addMonths(date: Date, months: number): Date
addYears(date: Date, years: number): Date
getDaysDifference(date1: Date, date2: Date): number
getHoursDifference(date1: Date, date2: Date): number
getMinutesDifference(date1: Date, date2: Date): number
isToday(date: Date): boolean
isYesterday(date: Date): boolean
isTomorrow(date: Date): boolean
isPast(date: Date): boolean
isFuture(date: Date): boolean
getAge(birthDate: Date): number
isLeapYear(year: number): boolean
getDaysInMonth(year: number, month: number): number
formatDateLocale(date: Date, locale?: string, options?: Intl.DateTimeFormatOptions): string

Currency & Number Formatters

formatCurrency(amount: number, currency?: string, locale?: string): string
formatCompactNumber(num: number): string       // e.g., 1.5K, 2M
formatFileSize(bytes: number): string
formatPercentage(value: number, decimals?: number, locale?: string): string
formatNumber(num: number, locale?: string, options?: Intl.NumberFormatOptions): string
formatCreditCard(cardNumber: string, mask?: boolean): string
formatSSN(ssn: string, mask?: boolean): string
formatPostalCode(postalCode: string): string
formatDuration(seconds: number): string
formatRelativeTime(date: Date | string | number): string
formatOrdinal(num: number): string
formatBytes(bytes: number, decimals?: number): string

Comprehensive Examples:

// Currency formatting
formatCurrency(1234.56); // $1,234.56
formatCurrency(1234.56, 'EUR', 'de-DE'); // 1.234,56 €
formatCurrency(1234.56, 'JPY', 'ja-JP'); // ¥1,235

// Compact number formatting
formatCompactNumber(1500); // 1.5K
formatCompactNumber(2000000); // 2.0M
formatCompactNumber(1500000000); // 1.5B

// File size formatting
formatFileSize(1024); // 1 KB
formatFileSize(1048576); // 1 MB
formatBytes(1024, 2); // 1.00 KB

// Percentage formatting
formatPercentage(12.5); // 12.50%
formatPercentage(0.5, 1); // 0.5%

// Personal data formatting
formatCreditCard('4111111111111111', true); // ************1111
formatSSN('123456789', true); // ***-**-6789
formatPostalCode('123456789'); // 12345-6789

// Time formatting
formatDuration(3661); // 1h 1m 1s
formatRelativeTime(new Date(Date.now() - 2 * 60 * 60 * 1000)); // 2 hours ago
formatOrdinal(21); // 21st
formatOrdinal(22); // 22nd

// Number formatting with options
formatNumber(1234.56, 'en-US', { 
    style: 'currency', 
    currency: 'USD' 
}); // $1,234.56

formatNumber(0.1234, 'en-US', { 
    style: 'percent' 
}); // 12%

Real-World Usage:

// E-commerce product display
const product = {
    name: 'Premium Headphones',
    price: 299.99,
    discount: 15,
    fileSize: 1048576,
    rating: 4.5
};

console.log(`Product: ${product.name}`);
console.log(`Price: ${formatCurrency(product.price, 'USD')}`);
console.log(`Discount: ${formatPercentage(product.discount)}`);
console.log(`Final Price: ${formatCurrency(product.price * (1 - product.discount / 100), 'USD')}`);
console.log(`File Size: ${formatFileSize(product.fileSize)}`);
console.log(`Rating: ${formatNumber(product.rating, 'en-US', { minimumFractionDigits: 1, maximumFractionDigits: 1 })}/5`);

Currency Utilities (Locale-based)

Get currency information (code, symbol, name) from locale strings. Supports 50+ countries including Israel, UAE, USA, and Asian countries.

getCurrencyByLocale(locale: string): CurrencyInfo | null
getCurrencyCode(locale: string): string | null
getCurrencySymbol(locale: string): string | null
hasCurrencyMapping(locale: string): boolean
getSupportedCountryCodes(): string[]
getAllCurrencies(): CurrencyInfo[]

// Types
interface CurrencyInfo {
  code: string;    // ISO 4217 currency code (e.g., 'ILS', 'USD')
  symbol: string;  // Currency symbol (e.g., '₪', '$')
  name: string;    // Full currency name (e.g., 'Israeli New Shekel')
}

Supported Locale Formats:

The utility handles various locale string formats:

  • Country code only: IL, US, AE
  • Language-Country with slash: he/IL, en/US, ar/AE
  • Language-Country with dash (BCP 47): he-IL, en-US, ar-AE
  • Language-Country with underscore: he_IL, en_US, ar_AE
  • Case-insensitive: il, IL, Il

Examples:

// Israel - all formats return ILS
getCurrencyByLocale('he/IL'); // { code: 'ILS', symbol: '₪', name: 'Israeli New Shekel' }
getCurrencyByLocale('IL');    // { code: 'ILS', symbol: '₪', name: 'Israeli New Shekel' }
getCurrencyByLocale('he-IL'); // { code: 'ILS', symbol: '₪', name: 'Israeli New Shekel' }
getCurrencyByLocale('ar-IL'); // { code: 'ILS', symbol: '₪', name: 'Israeli New Shekel' }

// Get just the currency code
getCurrencyCode('he/IL'); // 'ILS'
getCurrencyCode('IL');    // 'ILS'
getCurrencyCode('US');    // 'USD'
getCurrencyCode('ar-AE'); // 'AED'

// Get just the currency symbol
getCurrencySymbol('IL');    // '₪'
getCurrencySymbol('US');    // '$'
getCurrencySymbol('en-GB'); // '£'
getCurrencySymbol('ar-AE'); // 'د.إ'

// UAE and other Asian countries
getCurrencyCode('ar-AE'); // 'AED' (UAE Dirham)
getCurrencyCode('ar-SA'); // 'SAR' (Saudi Riyal)
getCurrencyCode('ja-JP'); // 'JPY' (Japanese Yen)
getCurrencyCode('zh-CN'); // 'CNY' (Chinese Yuan)
getCurrencyCode('ko-KR'); // 'KRW' (South Korean Won)
getCurrencyCode('hi-IN'); // 'INR' (Indian Rupee)

// Check if locale has currency mapping
hasCurrencyMapping('IL');     // true
hasCurrencyMapping('he-IL');  // true
hasCurrencyMapping('xyz-XYZ'); // false

// Get all supported country codes
const codes = getSupportedCountryCodes();
// ['IL', 'AE', 'SA', 'QA', 'KW', 'US', 'GB', 'DE', ...]

// Get all unique currencies
const currencies = getAllCurrencies();
currencies.forEach(currency => {
  console.log(`${currency.code} (${currency.symbol}) - ${currency.name}`);
});
// ILS (₪) - Israeli New Shekel
// USD ($) - US Dollar
// EUR (€) - Euro
// ...

Supported Regions: 50+ countries including:

  • 🇮🇱 Israel, 🇦🇪 UAE, 🇸🇦 Saudi Arabia, 🇶🇦 Qatar, 🇰🇼 Kuwait (Middle East)
  • 🇯🇵 Japan, 🇨🇳 China, 🇰🇷 South Korea, 🇮🇳 India, 🇸🇬 Singapore, 🇹🇭 Thailand (Asia)
  • 🇺🇸 USA, 🇨🇦 Canada, 🇲🇽 Mexico, 🇧🇷 Brazil (Americas)
  • 🇬🇧 UK, 🇩🇪 Germany, 🇫🇷 France, 🇪🇸 Spain (Europe)
  • 🇦🇺 Australia, 🇳🇿 New Zealand (Oceania)

Real-World Usage:

// Multi-currency e-commerce
const getUserCurrency = (userLocale: string) => {
  const currency = getCurrencyByLocale(userLocale);
  if (currency) {
    return formatCurrency(product.price, currency.code, userLocale);
  }
  return formatCurrency(product.price, 'USD', 'en-US'); // Fallback
};

// Internationalization setup
const initializeApp = (locale: string) => {
  const currencyInfo = getCurrencyByLocale(locale);
  if (currencyInfo) {
    config({
      defaultLanguage: locale.split(/[/-_]/)[0],
      defaultCurrency: currencyInfo.code,
      defaultRegion: locale.split(/[/-_]/)[1] || 'US'
    });
  }
};

// Display currency selector
const CurrencySelector = ({ currentLocale }: { currentLocale: string }) => {
  const currencies = getAllCurrencies();
  const currentCurrency = getCurrencyByLocale(currentLocale);
  
  return (
    <select value={currentCurrency?.code}>
      {currencies.map(currency => (
        <option key={currency.code} value={currency.code}>
          {currency.symbol} {currency.name}
        </option>
      ))}
    </select>
  );
};

For complete documentation, see Currency Utilities Documentation.

Phone Number Formatting

formatPhoneNumber(
  phone: string,
  format: "PPP - EEE SSSS" | "(PPP) - EEE SSSS" | "(PP)  EEE SSSS" | "PP-EEE SSSS" | "PPP-EEE SSSS" | "+C (PPP)-EEE-SSSS" | "+C (PPP) EEESSSS" | "E.164" | string,
  options?: {
    leadingDigitPad?: string
    inputIncludesCountry?: boolean | "autoDetect"
    nationalNumberLength?: number
    originCountry?: keyof typeof COUNTRY_CODES
  }
): string

// Country codes constant
COUNTRY_CODES: {
  IL: 972, US: 1, CA: 1, GB: 44, FR: 33, DE: 49, IT: 39, ES: 34, NL: 31, BE: 32, CH: 41, AT: 43, SE: 46, NO: 47, DK: 45, FI: 358, IE: 353, AU: 61, NZ: 64, AE: 971, SA: 966, JO: 962, EG: 20, TR: 90
}

E.164 format

  • What it is: International standard, + country code + national number (no spaces/dashes/parentheses)
  • Behavior: Removes a single leading national trunk 0 from the national number when present
// Without country code (uses originCountry)
formatPhoneNumber('0502892553', 'E.164', { originCountry: 'IL' });
// '+972502892553'

// With country code in input
formatPhoneNumber('+9720502892553', 'E.164');
// '+972502892553'

Context System (Global Configuration)

Initialize the library once with your preferred settings:

import { config } from '@apx-ui/toolkit';

// Initialize library on app startup
config({
    defaultLanguage: 'en',
    defaultCurrency: 'USD', 
    defaultTimezone: 'America/New_York',
    persist: 'localStorage', // 'localStorage' | 'sessionStorage' | 'memory' | false
    debug: false
});

Context Functions:

// Configuration
config(options: ApxContextOptions): void

// Language & Locale
setLanguage(language: string): void
getLanguage(): string
setLocale(locale: string): void
getLocale(): string

// Currency & Timezone  
setCurrency(currency: string): void
getCurrency(): string
setTimezone(timezone: string): void
getTimezone(): string

// Utilities
resetContext(): void
isInitialized(): boolean
isBrowser(): boolean

Storage Options:

persist: 'localStorage'    // Persists across browser sessions
persist: 'sessionStorage'  // Persists until tab closes  
persist: 'memory'          // In-memory only (no persistence)
persist: false             // No persistence, always use defaults

Singleton Behavior: The context system is a singleton, meaning:

  • Initialize once at app startup with config()
  • Subsequent config() calls are ignored if already initialized
  • Use resetContext() to clear and reinitialize if needed
  • Perfect for SPAs where you want settings to persist across route changes

I18N Formatters (Internationalization)

formatCurrencyI18N(amount: number, currency?: string, locale?: string): string
formatDateI18N(date: Date | string | number, format?: string, variant?: 'appointment' | 'default', locale?: string): string
formatTimeI18N(value: number, unit: TimeUnit, locale?: string): string

Context-Aware Usage (Recommended):

import { config, formatCurrencyI18N, setLanguage } from '@apx-ui/toolkit';

// Initialize once
config({ defaultCurrency: 'USD', defaultLanguage: 'en' });

// Use formatters without parameters - they read from context
formatCurrencyI18N(1234.56); // Uses context currency & locale

// Change context globally
setLanguage('he');
formatCurrencyI18N(1234.56); // Now uses Hebrew locale & context currency

// Override context per call
formatCurrencyI18N(1234.56, 'EUR', 'de-DE'); // German Euro formatting

Legacy Functions (Deprecated):

setCurrentLanguage(languageCode: keyof typeof LANGUAGES): void  // Use setLanguage instead
setCurrentLocale(locale: string): void                         // Use setLocale instead  
getCurrentLocale(): string                                     // Use getLocale instead
getCurrentLanguageCode(): keyof typeof LANGUAGES              // Use getLanguage instead
getCurrentLocaleFromStorage(): string | null
isBrowser(): boolean                                           // Use context system instead

Constants

Countries

Languages & Translations

// Language codes and locales
LANGUAGES: Record<string, ApxLanguageObject>
RTL_LANGUAGES: string[]

// Translation functions and data
getLocaleConjunction(locale: string): string
getTimeUnitTranslation(locale: string, unit: TimeUnit, value: number): string
getDayTranslation(language: string, day: DayName, format: 'short' | 'long'): string
getMonthTranslation(language: string, month: MonthName, format: 'short' | 'long'): string
getDaysForLanguage(language: string): Record<DayName, DayTranslation>
getMonthsForLanguage(language: string): Record<MonthName, MonthTranslation>

// Translation constants
LOCALE_CONJUNCTIONS: Record<string, string>
TIME_UNIT_TRANSLATIONS: Record<string, Record<TimeUnit, { singular: string; plural: string }>>
DAYS_TRANSLATIONS: Record<string, Record<DayName, DayTranslation>>
MONTHS_TRANSLATIONS: Record<string, Record<MonthName, MonthTranslation>>

// Types
TimeUnit: 'ms' | 's' | 'm' | 'h' | 'd' | 'w' | 'mo' | 'y'
DayName: 'sunday' | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday'
MonthName: 'january' | 'february' | 'march' | 'april' | 'may' | 'june' | 'july' | 'august' | 'september' | 'october' | 'november' | 'december'
COUNTRIES = [
  { code: 'US', name: 'United States', phoneCode: '+1' },
  { code: 'IL', name: 'Israel', phoneCode: '+972' },
  ...
]

getCountryByCode(code: string): Country | undefined
getCountryByName(name: string): Country | undefined
getCountriesByPhoneCode(phoneCode: string): Country[]

Languages

LANGUAGES = [
  { code: 'en', label: 'English', nativeName: 'English' },
  { code: 'he', label: 'Hebrew', nativeName: 'עברית' },
  ...
]

getLanguageByCode(code: string): Language | undefined
getLanguageByLabel(label: string): Language | undefined
getSupportedLanguageCodes(): string[]

Magic Numbers

SECONDS_IN_MINUTE = 60
MILLISECONDS_IN_SECOND = 1000
MILLISECONDS_IN_MINUTE = 60000
NUMBER_1000 = 1000
// ... and many more time and mathematical constants

Region & Currency Mapping

REGION_CURRENCY_MAP: Record<string, string>  // Maps country codes to currency codes
getCurrencyForRegion(region: string): string | undefined
getSupportedRegions(): string[]
getSupportedCurrencies(): string[]

// Examples:
getCurrencyForRegion('US') // 'USD'
getCurrencyForRegion('IL') // 'ILS'
getCurrencyForRegion('GB') // 'GBP'

Regex Patterns

REGEX = {
  email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
  phone: /^(\+?\d{1,3})?\d{7,14}$/,
  numeric: /^\d+$/,
  url: /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/i,
  strongPassword: /^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$/,
  // ... and many more patterns
}

Generic Helpers

isEmpty(value: any): boolean
isDefined<T>(val: T | undefined | null): val is T
toNumberSafe(value: any, fallback = 0): number
isString(value: any): value is string
isNumber(value: any): value is number
isBoolean(value: any): value is boolean
isObject(value: any): value is object
isArray(value: any): value is any[]
isFunction(value: any): value is Function
isNull(value: any): value is null
isUndefined(value: any): value is undefined
getValueOrFallback<T>(value: T | null | undefined, fallback: T): T
deepClone<T>(obj: T): T
pick<T extends object, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>
omit<T extends object, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>
debounce<T extends (...args: any[]) => any>(func: T, delay: number): (...args: Parameters<T>) => void
throttle<T extends (...args: any[]) => any>(func: T, delay: number): (...args: Parameters<T>) => void
randomString(length?: number): string
randomNumber(min: number, max: number): number
capitalize(str: string): string
toCamelCase(str: string): string
toKebabCase(str: string): string
toSnakeCase(str: string): string
toPascalCase(str: string): string
truncate(str: string, length: number, suffix?: string): string
unique<T>(array: T[]): T[]
groupBy<T, K extends keyof T>(array: T[], key: K): Record<string, T[]>
sortBy<T, K extends keyof T>(array: T[], key: K, order?: 'asc' | 'desc'): T[]

Comprehensive Examples:

// Type checking
isEmpty(''); // true
isEmpty([]); // true
isEmpty({}); // true
isEmpty('hello'); // false

isDefined(null); // false
isDefined(undefined); // false
isDefined('hello'); // true

isString('hello'); // true
isNumber(123); // true
isBoolean(true); // true
isArray([1, 2, 3]); // true
isObject({}); // true

// Safe value conversion
toNumberSafe('123'); // 123
toNumberSafe('abc', 0); // 0
toNumberSafe(null, 999); // 999

getValueOrFallback(null, 'default'); // 'default'
getValueOrFallback('hello', 'default'); // 'hello'

// Object manipulation
const user = { id: 1, name: 'John', email: '[email protected]', age: 30 };

const userBasic = pick(user, ['name', 'email']); // { name: 'John', email: '[email protected]' }
const userWithoutId = omit(user, ['id', 'age']); // { name: 'John', email: '[email protected]' }

// Deep cloning
const original = { user: { name: 'John' }, items: [1, 2, 3] };
const cloned = deepClone(original);
cloned.user.name = 'Jane';
console.log(original.user.name); // 'John' (unchanged)

// String utilities
capitalize('hello world'); // 'Hello world'
toCamelCase('hello-world'); // 'helloWorld'
toKebabCase('helloWorld'); // 'hello-world'
toSnakeCase('helloWorld'); // 'hello_world'
toPascalCase('hello world'); // 'HelloWorld'
truncate('This is a very long string', 20, '...'); // 'This is a very long...'

// Array utilities
unique([1, 2, 2, 3, 3, 3]); // [1, 2, 3]

const users = [
    { name: 'John', department: 'Engineering', age: 30 },
    { name: 'Jane', department: 'Marketing', age: 25 },
    { name: 'Bob', department: 'Engineering', age: 35 }
];

groupBy(users, 'department');
// { Engineering: [{ name: 'John', ... }, { name: 'Bob', ... }], Marketing: [{ name: 'Jane', ... }] }

sortBy(users, 'age'); // Sort by age ascending
sortBy(users, 'age', 'desc'); // Sort by age descending
// Performance Utility

// Debounce

// JS Example:
const debouncedSearch = debounce((query: string) => {
    console.log('Searching for:', query);
}, 300);

// React onClick example:

<button onClick={debounce(() => console.log("Clicked!"), 500)}>
  Click me
</button>
/**
 * 
 * If the user clicks 5 times rapidly:
 - All previous timers get canceled.
 - After 500ms of no further clicks, the callback fires once.
 
 * Effect: “Only run after the last click in a burst.”
 */


// Throttle

// JS Example:
const throttledScroll = throttle(() => {
    console.log('Scroll event');
}, 100);

// React onClick example:
<button onClick={throttle(() => console.log("Clicked!"), 1000)}>
  Click me
</button>

/**
 * 
 * If the user clicks 5 times rapidly:
   - First click triggers immediately.
  - Next clicks within 1000ms are ignored.
  - After 1000ms, another click will be accepted.

 * Effect: “Run immediately, then ignore until delay passes.”
*/
// Random utilities
randomString(10); // 'aB3xY9mK2p'
randomNumber(1, 100); // Random number between 1 and 100

Real-World Usage:

// Form data sanitization
const sanitizeFormData = (data: any) => {
    return {
        name: data.name?.trim() || '',
        email: data.email?.trim() || '',
        age: toNumberSafe(data.age, 0),
        phone: data.phone?.replace(/\D/g, '') || '',
        bio: truncate(data.bio?.trim() || '', 100, '...')
    };
};

// Data processing pipeline
const processUsers = (users: any[]) => {
    // Filter out invalid users
    const validUsers = users.filter(user => 
        isDefined(user.name) && 
        isDefined(user.email) && 
        !isEmpty(user.name)
    );
    
    // Group by department
    const byDepartment = groupBy(validUsers, 'department');
    
    // Sort by name
    const sorted = sortBy(validUsers, 'name');
    
    return { validUsers, byDepartment, sorted };
};

// API response handling
const handleApiResponse = (response: any) => {
    const data = getValueOrFallback(response.data, []);
    const error = getValueOrFallback(response.error, null);
    
    if (isDefined(error)) {
        console.error('API Error:', error);
        return [];
    }
    
    return isArray(data) ? data : [];
};

Scroll Utilities

scrollToTop(options?: ScrollOptions): void
scrollToElement(element: Element, options?: ScrollOptions, offset?: number): void
scrollToPosition(position: number, options?: ScrollOptions): void
isInViewport(element: Element, threshold?: number): boolean
getScrollPosition(target?: Window | Element): number
stopScroll(target?: Window | Element): void

// Types
type ScrollBehavior = 'auto' | 'smooth'
interface ScrollOptions {
  behavior?: ScrollBehavior
  duration?: number
  easing?: 'linear' | 'easeInOut' | 'easeIn' | 'easeOut'
  target?: Window | Element
}

Credit Card Utilities

// Credit card formatting
formatCreditCard(cardNumber: string, options?: CreditCardFormatOptions): string
getCreditCardType(cardNumber: string): CreditCardType | null
getLast4Digits(cardNumber: string): string
maskCreditCard(cardNumber: string, maskChar?: string): string

// Credit card validation
isValidCreditCardNumber(cardNumber: string): boolean

// Dummy card generation
getRandomDummyCreditCard(type?: CreditCardType): string

// Credit card information
getCreditCardInfo(cardNumber: string, options?: CreditCardFormatOptions): CreditCardInfo
getAvailableCreditCardTypes(): Array<{ type: CreditCardType; name: string; format: string }>

// Types
type CreditCardType = 'VISA' | 'MASTERCARD' | 'AMERICAN_EXPRESS' | 'DISCOVER' | 'DINERS_CLUB' | 'JCB' | 'UNIONPAY'
type CreditCardFormatOptions = {
  mask?: boolean
  format?: string
  maskChar?: string
}
type CreditCardInfo = {
  type: CreditCardType | null
  typeName: string | null
  number: string
  formatted: string
  last4: string
  isValid: boolean
  length: number
}

Comprehensive Examples:

// Basic formatting
formatCreditCard('4111111111111111'); // '4111 1111 1111 1111'

// Custom format with placeholders
formatCreditCard('4111111111111111', { 
  format: 'AAAA-BBBB-CCCC-DDDD' 
}); // '4111-1111-1111-1111'

// Masked formatting
formatCreditCard('4111111111111111', { 
  mask: true 
}); // '************1111'

// Custom mask character
formatCreditCard('4111111111111111', { 
  mask: true, 
  maskChar: 'X' 
}); // 'XXXXXXXXXXXX1111'

// Credit card type detection
getCreditCardType('4111111111111111'); // 'VISA'
getCreditCardType('5555555555554444'); // 'MASTERCARD'

// Last 4 digits
getLast4Digits('4111111111111111'); // '1111'

// Validation
isValidCreditCardNumber('4111111111111111'); // true
isValidCreditCardNumber('1234567890123456'); // false

// Dummy card generation
getRandomDummyCreditCard('VISA'); // '4111111111111111'
getRandomDummyCreditCard(); // Random card of any type

// Complete card information
const info = getCreditCardInfo('4111111111111111');
console.log(info);
// {
//   type: 'VISA',
//   typeName: 'Visa',
//   number: '4111111111111111',
//   formatted: '4111 1111 1111 1111',
//   last4: '1111',
//   isValid: true,
//   length: 16
// }

Supported Credit Card Types:

  • Visa: 4xxx (13, 16, 19 digits)
  • MasterCard: 5xxx (16 digits)
  • American Express: 3x (15 digits)
  • Discover: 6xxx (16 digits)
  • Diners Club: 3xxx (14 digits)
  • JCB: 3xxx (15, 16 digits)
  • UnionPay: 62xx (16-19 digits)

Real-World Usage:

// Payment form validation
const validatePaymentForm = (cardNumber: string) => {
  const info = getCreditCardInfo(cardNumber);
  
  if (!info.isValid) {
    return { valid: false, error: 'Invalid credit card number' };
  }
  
  return {
    valid: true,
    type: info.typeName,
    last4: info.last4,
    formatted: info.formatted
  };
};

// Display saved cards
const displaySavedCards = (cards: string[]) => {
  return cards.map(card => {
    const info = getCreditCardInfo(card);
    return {
      type: info.typeName,
      last4: info.last4,
      masked: maskCreditCard(card)
    };
  });
};

// Test card generation for development
const generateTestCards = () => {
  return {
    visa: getRandomDummyCreditCard('VISA'),
    mastercard: getRandomDummyCreditCard('MASTERCARD'),
    amex: getRandomDummyCreditCard('AMERICAN_EXPRESS')
  };
};

Opening Hours Formatter

formatOpeningHours(
  storeHours: StoreHours,
  options?: {
    locale?: string
    use24Hour?: boolean
    language?: string
  }
): string[]

// Types
type StoreHours = Array<{
  open: string | false
  closed: string | false
} | Array<{
  open: string
  closed: string
}>>

Comprehensive Examples:

// Standard business hours
const standardHours: StoreHours = [
    { "closed": false, "open": false }, // Sunday - Closed
    [{ "closed": "17:00", "open": "09:00" }], // Monday - 9:00-17:00
    [{ "closed": "17:00", "open": "09:00" }], // Tuesday - 9:00-17:00
    [{ "closed": "17:00", "open": "09:00" }], // Wednesday - 9:00-17:00
    [{ "closed": "17:00", "open": "09:00" }], // Thursday - 9:00-17:00
    [{ "closed": "17:00", "open": "09:00" }], // Friday - 9:00-17:00
    [{ "closed": "15:00", "open": "09:00" }]  // Saturday - 9:00-15:00
];

// English with 12-hour format
const englishHours = formatOpeningHours(standardHours, {
    locale: 'en-US',
    use24Hour: false,
    language: 'en'
});
// ['Sunday, Saturday: 9:00 AM - 6:00 PM', 'Monday - Friday: 9:00 AM - 5:00 PM']

// Hebrew with 12-hour format
const hebrewHours = formatOpeningHours(standardHours, {
    locale: 'he-IL',
    use24Hour: false,
    language: 'he'
});
// ['ראשון, שבת: 9:00 AM - 6:00 PM', 'שני - שישי: 9:00 AM - 5:00 PM']

// Arabic with 24-hour format
const arabicHours = formatOpeningHours(standardHours, {
    locale: 'ar-SA',
    use24Hour: true,
    language: 'ar'
});
// ['الأحد, السبت: ٠٩:٠٠ - ١٨:٠٠', 'الاثنين - الجمعة: ٠٩:٠٠ - ١٧:٠٠']

// Restaurant with lunch break
const restaurantHours: StoreHours = [
    { "closed": false, "open": false }, // Sunday - Closed
    [
        { "closed": "14:00", "open": "11:00" },
        { "closed": "22:00", "open": "17:00" }
    ], // Monday - 11:00-14:00, 17:00-22:00
    // ... similar for other days
];

const restaurantFormatted = formatOpeningHours(restaurantHours, {
    locale: 'en-US',
    use24Hour: false,
    language: 'en'
});
// ['Monday - Saturday: 11:00 AM - 2:00 PM, 5:00 PM - 10:00 PM', 'Sunday: Closed']

// 24/7 Store
const store24_7: StoreHours = [
    [{ "closed": "23:59", "open": "00:00" }], // Sunday - 24/7
    [{ "closed": "23:59", "open": "00:00" }], // Monday - 24/7
    // ... similar for all days
];

const store24_7Formatted = formatOpeningHours(store24_7, {
    locale: 'en-US',
    use24Hour: true,
    language: 'en'
});
// ['Sunday - Saturday: 00:00 - 23:59']

Real-World Usage:

// Business hours display component
const BusinessHoursDisplay = ({ hours, locale = 'en-US' }: { hours: StoreHours, locale?: string }) => {
    const formattedHours = formatOpeningHours(hours, {
        locale,
        use24Hour: false,
        language: locale.split('-')[0]
    });
    
    return (
        <div className="business-hours">
            <h3>Opening Hours</h3>
            {formattedHours.map((line, index) => (
                <p key={index}>{line}</p>
            ))}
        </div>
    );
};

// Multi-language support
const getBusinessHours = (language: string) => {
    const hours = getStoreHours(); // Your business hours data
    
    return formatOpeningHours(hours, {
        locale: `${language}-${getCountryCode(language)}`,
        use24Hour: language === 'ar' || language === 'he', // Use 24-hour for Arabic/Hebrew
        language
    });
};

Storage Persister

// Main Persister class
Persister.setLocalStorage(data: PersisterData): void
Persister.getLocalStorage<T>(key: string): T | null
Persister.removeLocalStorage(key: string): void
Persister.setSessionStorage(data: PersisterData): void
Persister.getSessionStorage<T>(key: string): T | null
Persister.removeSessionStorage(key: string): void
Persister.has(key: string, storageType?: StorageType): boolean
Persister.keys(storageType?: StorageType): string[]
Persister.getStorageSize(storageType?: StorageType): number
Persister.clear(storageType?: StorageType): void
Persister.getRemainingTTL(key: string, storageType?: StorageType): number | null
Persister.cleanupExpiredTTL(storageType?: StorageType): void

// Convenience classes
LocalStorage.set(data: PersisterData): void
LocalStorage.get<T>(key: string): T | null
LocalStorage.remove(key: string): void
LocalStorage.has(key: string): boolean
LocalStorage.keys(): string[]
LocalStorage.clear(): void
LocalStorage.cleanupExpiredTTL(): void
LocalStorage.getRemainingTTL(key: string): number | null

SessionStorage.set(data: PersisterData): void
SessionStorage.get<T>(key: string): T | null
SessionStorage.remove(key: string): void
SessionStorage.has(key: string): boolean
SessionStorage.keys(): string[]
SessionStorage.clear(): void
SessionStorage.cleanupExpiredTTL(): void
SessionStorage.getRemainingTTL(key: string): number | null

// Types
type PersisterData = Record<string, {
  value: any
  encode?: boolean
  ttl?: number
}>
type StorageType = 'localStorage' | 'sessionStorage'

Directory Structure

src/
├── constants/
│   ├── countries.ts
│   ├── languages.ts
│   ├── magicNumbers.ts
│   ├── days.ts
│   ├── months.ts
│   ├── regions.ts
│   └── translations.ts
├── context/
│   └── index.ts
├── persister/
│   ├── index.ts
│   └── utils.ts
├── regex/
│   └── patterns.ts
├── utils/
│   ├── validators.ts
│   ├── formatters.ts
│   ├── dateUtils.ts
│   ├── generic.ts
│   ├── i18nFormatters.ts
│   ├── phoneNumber.ts
│   └── scrollUtils.ts
├── common-types/
│   └── index.ts
└── index.ts

Usage Examples

Validation

import { isEmail, validateEmail, isPhone, isStrongPassword } from '@apx-ui/toolkit';

// Simple validation
isEmail('[email protected]'); // true
isPhone('+1234567890'); // true
isStrongPassword('MyPass123!'); // true

// Detailed validation with error messages
const emailResult = validateEmail('invalid-email');
console.log(emailResult); // { valid: false, error: 'Invalid email format' }

Formatting

import { formatCurrency, formatPhoneNumber, formatCompactNumber } from '@apx-ui/toolkit';

formatCurrency(1234.56, 'USD', 'en-US'); // '$1,234.56'
formatPhoneNumber('+12345678901', '+C (PPP)-EEE-SSSS'); // '+1 (234)-567-8901'
formatPhoneNumber('1234567890', 'PPP - EEE SSSS'); // '123 - 456 7890'
formatCompactNumber(1500); // '1.5K'

Date Utilities

import { formatDate, getTimeAgo, isToday, addDays } from '@apx-ui/toolkit';

formatDate(new Date(), 'YYYY-MM-DD'); // '2024-01-15'
getTimeAgo(new Date('2024-01-10')); // '5 days ago'
isToday(new Date()); // true
addDays(new Date(), 7); // Date object 7 days from now

Generic Helpers

import { isEmpty, isDefined, toNumberSafe, deepClone } from '@apx-ui/toolkit';

isEmpty(''); // true
isEmpty([]); // true
isEmpty({}); // true

isDefined(null); // false
isDefined(undefined); // false
isDefined('hello'); // true

toNumberSafe('123'); // 123
toNumberSafe('abc', 0); // 0

const obj = { a: 1, b: { c: 2 } };
const cloned = deepClone(obj); // Deep copy

Constants

import { COUNTRIES, LANGUAGES, SECONDS_IN_MINUTE, getCurrencyForRegion } from '@apx-ui/toolkit';

const israel = COUNTRIES.find(c => c.code === 'IL');
console.log(israel); // { code: 'IL', name: 'Israel', phoneCode: '+972' }

const english = LANGUAGES.find(l => l.code === 'en');
console.log(english); // { code: 'en', label: 'English', nativeName: 'English' }

console.log(SECONDS_IN_MINUTE); // 60
console.log(getCurrencyForRegion('US')); // 'USD'

Scroll Utilities

import { scrollToTop, scrollToElement, isInViewport } from '@apx-ui/toolkit';

// Smooth scroll to top
scrollToTop({ duration: 1000, easing: 'easeInOut' });

// Scroll to element with offset
const element = document.getElementById('section');
scrollToElement(element, { duration: 500 }, 100);

// Check if element is visible
const isVisible = isInViewport(element, 0.5); // 50% threshold

Storage Persister

import { LocalStorage, SessionStorage } from '@apx-ui/toolkit';

// Store data with TTL (time to live)
LocalStorage.set({
  user: { value: { id: 1, name: 'John' }, ttl: 3600 }, // Expires in 1 hour
  settings: { value: { theme: 'dark' } } // No expiration
});

// Retrieve data
const user = LocalStorage.get('user');
const settings = LocalStorage.get('settings');

// Check if key exists and get remaining TTL
if (LocalStorage.has('user')) {
  const remainingTime = LocalStorage.getRemainingTTL('user'); // seconds
  console.log(`User data expires in ${remainingTime} seconds`);
}

// Clean up expired items
LocalStorage.cleanupExpiredTTL();

Testing

npm test

Contributing

  1. Clone the repo
  2. Install deps: npm install
  3. Run tests: npm test
  4. Add your utility to src/ and export it in index.ts

PRs and suggestions are welcome!


License

MIT © 2025 AppNA.io