This directory contains shared utility functions used throughout the application. These utilities provide consistent, reusable functionality for common operations.
classNames.ts - ClassName ManagementThe cn() function provides flexible className concatenation with support for conditional classes.
import { cn } from "../utils/classNames"
// Basic usage
cn("foo", "bar") // => 'foo bar'
// Conditional classes
cn("base", condition && "active") // => 'base active' or 'base'
cn("base", { active: isActive, disabled: isDisabled }) // => 'base active' or 'base disabled'
// Filters out falsy values
cn("foo", undefined, null, false, "bar") // => 'foo bar'
// Arrays and nested structures
cn(["foo", "bar"], condition && "baz") // => 'foo bar baz'
Use Cases:
formatting.ts - Data FormattingComprehensive formatting utilities for numbers, dates, file sizes, and text.
import { formatK, formatKM, formatCost, formatPercentage } from "../utils/formatting"
formatK(1500) // => "2K"
formatK(1500000) // => "1.5M"
formatKM(1500) // => "1.5K" (shows decimals for K)
formatCost(12.5) // => "$12.50"
formatPercentage(0.756, 1) // => "75.6%"
import { formatDate, formatDateTime, formatTimestamp, formatRelativeTime, formatDuration } from "../utils/formatting"
formatDate(new Date()) // => "12/31/2023"
formatDateTime(new Date()) // => "12/31/2023, 11:59:59 PM"
formatTimestamp(1234567890000) // => "2009-02-13 23:31"
formatRelativeTime(Date.now() - 3600000) // => "1 hour ago"
formatDuration(65000) // => "1m 5s"
import { formatFileSize } from "../utils/formatting"
formatFileSize(1024) // => "1.0KB"
formatFileSize(1536) // => "1.5KB"
formatFileSize(1048576) // => "1.0MB"
import { truncate, capitalize, toTitleCase } from "../utils/formatting"
truncate("Hello World", 8) // => "Hello..."
capitalize("hello") // => "Hello"
toTitleCase("hello world") // => "Hello World"
validation.ts - Input ValidationValidation utilities for form inputs and data validation.
import { isEmpty, isNotEmpty, isValidEmail, isValidUrl, isValidHttpUrl } from "../utils/validation"
isEmpty("") // => true
isEmpty(" ") // => true
isNotEmpty("hello") // => true
isValidEmail("[email protected]") // => true
isValidUrl("https://example.com") // => true
isValidHttpUrl("https://example.com") // => true
isValidHttpUrl("ftp://example.com") // => false
import { isNumber, isDigits, isInteger, isFloat, inRange } from "../utils/validation"
isNumber(123) // => true
isDigits("123") // => true
isInteger("123") // => true
isFloat("12.3") // => true
inRange(5, 1, 10) // => true
import {
isLengthInRange,
matches,
startsWithIgnoreCase,
endsWithIgnoreCase,
containsIgnoreCase,
} from "../utils/validation"
isLengthInRange("hello", 1, 10) // => true
matches("abc123", /^[a-z]+\d+$/) // => true
startsWithIgnoreCase("Hello", "hel") // => true
endsWithIgnoreCase("Hello", "LLO") // => true
containsIgnoreCase("Hello World", "WORLD") // => true
import { isStrongPassword } from "../utils/validation"
isStrongPassword("Abc123!@#") // => true
isStrongPassword("abc", {
minLength: 3,
requireUppercase: false,
requireDigits: false,
}) // => true
import { sanitizeHtml, hasRequiredFields } from "../utils/validation"
sanitizeHtml("<script>alert('xss')</script>") // => "alert('xss')"
hasRequiredFields({ name: "John", age: 30 }, ["name", "age"]) // => true
path.ts - Path UtilitiesPath manipulation utilities for file paths.
import { normalizePath, toProjectRelative, toDisplayPath, dirname, basename, extname, join } from "../utils/path"
// Normalize paths (convert backslashes, remove trailing slash)
normalizePath("C:\\Users\\test\\") // => "C:/Users/test"
// Convert to project-relative paths
toProjectRelative("/home/user/project/src/file.ts", "/home/user/project")
// => "src/file.ts"
// Get display-friendly paths
toDisplayPath("/home/user/project/src/file.ts", "/home/user/project")
// => "src/file.ts"
// Path components
dirname("/home/user/file.txt") // => "/home/user"
basename("/home/user/file.txt") // => "file.txt"
extname("file.txt") // => ".txt"
// Join path segments
join("src", "components", "Button.tsx") // => "src/components/Button.tsx"
Some utilities maintain backwards compatibility by re-exporting from their new location:
lib/path.ts - Now re-exports from utils/path.ts (deprecated but kept for compatibility)lib/fileUtils.ts - Re-exports formatFileSize from utils/formatting.tscomponents/CompactHeader/utils.ts - Re-exports formatting utilitiesWhen updating code, prefer importing directly from the utils directory:
// Old (deprecated, no longer works)
import { normalizePath } from "../lib/path"
// New (recommended)
import { normalizePath } from "../utils/path"
// Or use barrel export
import { normalizePath, formatFileSize, cn } from "../utils"
Type Safety: All utilities are fully typed. Use TypeScript's type checking to catch errors early.
Tree Shaking: Import only what you need to keep bundle size small:
// Good - only imports formatDate
import { formatDate } from "../utils/formatting"
// Less optimal - imports entire formatting module
import * as formatting from "../utils/formatting"
Consistent Usage: Use these utilities consistently across the codebase instead of creating one-off implementations.
Error Handling: Most utilities handle edge cases (null, undefined, empty strings), but always validate critical inputs.
Performance: These utilities are optimized for common use cases. For performance-critical code with millions of iterations, consider specialized implementations.
When adding new utilities:
index.ts if it should be publicly availableSee these files for real-world usage examples:
CodeBlock.tsx - Uses cn() for conditional classesModelSelector.tsx - Uses formatDate() for date formattingCompactHeader/utils.ts - Uses formatting utilities for numbers and costsMessageInput/hooks/useDragDrop.ts - Uses path utilitiesMessageList/CollapsiblePart.tsx - Uses cn() for dynamic styling