Getting Started
Get started with FoundryKit utilities for common development tasks
Getting Started
Learn how to install and use FoundryKit utilities to streamline common development tasks and improve code quality.
Installation
Install the Utils Package
Install the FoundryKit utils package in your project.
npm install @foundrykit/utils
Verify Installation
Check that the package is properly installed and accessible.
npm list @foundrykit/utils
Prerequisites
Before using FoundryKit utils, ensure you have the following:
- Node.js (v18 or higher)
- TypeScript (v4.9 or higher) - for type support
- React (v18 or higher) - for React-specific utilities
Check Your Environment
# Check Node.js version
node --version
# Check TypeScript version (if using TypeScript)
npx tsc --version
# Check React version
npm list react
Quick Start
Basic Usage
Import and use utilities in your project.
import { cn, formatDate, debounce, throttle } from '@foundrykit/utils'
// Class name utility
const className = cn('base-class', {
'active': isActive,
'disabled': isDisabled
})
// Date formatting
const formattedDate = formatDate(new Date(), 'MMM dd, yyyy')
// Function utilities
const debouncedSearch = debounce(searchFunction, 300)
const throttledScroll = throttle(scrollHandler, 100)
TypeScript Support
FoundryKit utils includes comprehensive TypeScript definitions.
import type { ClassValue, DateFormat, DebounceOptions } from '@foundrykit/utils'
// Type-safe usage
const classNames: ClassValue[] = ['base', { active: true }]
const format: DateFormat = 'yyyy-MM-dd'
const options: DebounceOptions = { leading: true, trailing: false }
Package Structure
The utils package is organized into logical modules for easy importing.
Utility Categories
Class Name Utilities
Handle conditional class names and styling.
import { cn, clsx } from '@foundrykit/utils'
// Conditional classes
const buttonClass = cn(
'px-4 py-2 rounded',
variant === 'primary' && 'bg-blue-600 text-white',
variant === 'secondary' && 'bg-gray-200 text-gray-900',
disabled && 'opacity-50 cursor-not-allowed'
)
// Complex class merging
const cardClass = clsx(
'card',
{
'card-elevated': elevated,
'card-interactive': interactive,
'card-loading': isLoading
},
className
)
Date Utilities
Format and manipulate dates consistently.
import { formatDate, parseDate, isValidDate, getRelativeTime } from '@foundrykit/utils'
// Format dates
const formatted = formatDate(new Date(), 'MMM dd, yyyy') // "Jan 15, 2024"
const iso = formatDate(new Date(), 'yyyy-MM-dd') // "2024-01-15"
// Parse dates
const date = parseDate('2024-01-15', 'yyyy-MM-dd')
// Validation
const isValid = isValidDate('2024-01-15')
// Relative time
const relative = getRelativeTime(new Date(Date.now() - 3600000)) // "1 hour ago"
Function Utilities
Optimize function calls with debouncing and throttling.
import { debounce, throttle, once, memoize } from '@foundrykit/utils'
// Debounce search input
const debouncedSearch = debounce((query: string) => {
performSearch(query)
}, 300)
// Throttle scroll events
const throttledScroll = throttle(() => {
updateScrollPosition()
}, 100)
// Execute only once
const initialize = once(() => {
setupApplication()
})
// Memoize expensive calculations
const memoizedCalculation = memoize((input: number) => {
return expensiveCalculation(input)
})
Object Utilities
Manipulate and work with objects safely.
import { pick, omit, deepMerge, isEqual, isEmpty } from '@foundrykit/utils'
// Pick specific properties
const userInfo = pick(user, ['name', 'email', 'avatar'])
// Omit properties
const publicUser = omit(user, ['password', 'apiKey'])
// Deep merge objects
const config = deepMerge(defaultConfig, userConfig)
// Compare objects
const hasChanged = !isEqual(previousData, currentData)
// Check if empty
const hasData = !isEmpty(responseData)
Array Utilities
Work with arrays more effectively.
import { unique, groupBy, sortBy, chunk, flatten } from '@foundrykit/utils'
// Remove duplicates
const uniqueItems = unique(items, 'id')
// Group by property
const groupedUsers = groupBy(users, 'department')
// Sort by property
const sortedProducts = sortBy(products, 'price')
// Split into chunks
const chunks = chunk(largeArray, 10)
// Flatten nested arrays
const flattened = flatten(nestedArray)
String Utilities
Format and manipulate strings.
import { capitalize, camelCase, kebabCase, truncate, slugify } from '@foundrykit/utils'
// Capitalize
const title = capitalize('hello world') // "Hello world"
// Case conversion
const camel = camelCase('hello-world') // "helloWorld"
const kebab = kebabCase('HelloWorld') // "hello-world"
// Truncate text
const excerpt = truncate(longText, 100)
// Create URL-friendly slugs
const slug = slugify('Hello World! 123') // "hello-world-123"
Validation Utilities
Validate data types and formats.
import { isEmail, isUrl, isPhoneNumber, isValidJSON, validateSchema } from '@foundrykit/utils'
// Email validation
const validEmail = isEmail('user@example.com')
// URL validation
const validUrl = isUrl('https://example.com')
// Phone number validation
const validPhone = isPhoneNumber('+1-555-123-4567')
// JSON validation
const validJson = isValidJSON('{"key": "value"}')
// Schema validation
const isValid = validateSchema(data, {
name: { type: 'string', required: true },
age: { type: 'number', min: 0 }
})
Integration Examples
React Component Example
import React, { useState, useMemo } from 'react'
import { cn, debounce, formatDate, truncate } from '@foundrykit/utils'
interface SearchableListProps {
items: Array<{
id: string
title: string
description: string
createdAt: Date
}>
className?: string
}
export function SearchableList({ items, className }: SearchableListProps) {
const [query, setQuery] = useState('')
// Debounced search
const debouncedSetQuery = useMemo(
() => debounce(setQuery, 300),
[]
)
// Filter items based on query
const filteredItems = useMemo(() => {
if (!query) return items
return items.filter(item =>
item.title.toLowerCase().includes(query.toLowerCase()) ||
item.description.toLowerCase().includes(query.toLowerCase())
)
}, [items, query])
return (
<div className={cn('searchable-list', className)}>
<input
type="text"
placeholder="Search..."
onChange={(e) => debouncedSetQuery(e.target.value)}
className="w-full p-2 border rounded"
/>
<div className="mt-4 space-y-2">
{filteredItems.map((item) => (
<div
key={item.id}
className={cn(
'p-4 border rounded',
'hover:bg-gray-50 transition-colors'
)}
>
<h3 className="font-semibold">{item.title}</h3>
<p className="text-gray-600 text-sm">
{truncate(item.description, 100)}
</p>
<time className="text-xs text-gray-500">
{formatDate(item.createdAt, 'MMM dd, yyyy')}
</time>
</div>
))}
</div>
</div>
)
}
Form Validation Example
import React, { useState } from 'react'
import { cn, isEmail, validateSchema, debounce } from '@foundrykit/utils'
interface FormData {
name: string
email: string
age: number
}
const formSchema = {
name: { type: 'string', required: true, minLength: 2 },
email: { type: 'string', required: true, validator: isEmail },
age: { type: 'number', required: true, min: 0, max: 120 }
}
export function ValidatedForm() {
const [formData, setFormData] = useState<FormData>({
name: '',
email: '',
age: 0
})
const [errors, setErrors] = useState<Record<string, string>>({})
// Debounced validation
const validateField = useMemo(
() => debounce((field: keyof FormData, value: any) => {
const fieldSchema = { [field]: formSchema[field] }
const fieldData = { [field]: value }
const validation = validateSchema(fieldData, fieldSchema)
setErrors(prev => ({
...prev,
[field]: validation.errors[field] || ''
}))
}, 300),
[]
)
const handleInputChange = (field: keyof FormData, value: any) => {
setFormData(prev => ({ ...prev, [field]: value }))
validateField(field, value)
}
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
const validation = validateSchema(formData, formSchema)
if (validation.isValid) {
console.log('Form is valid:', formData)
} else {
setErrors(validation.errors)
}
}
return (
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="name" className="block text-sm font-medium">
Name
</label>
<input
id="name"
type="text"
value={formData.name}
onChange={(e) => handleInputChange('name', e.target.value)}
className={cn(
'mt-1 block w-full px-3 py-2 border rounded-md',
errors.name && 'border-red-500'
)}
/>
{errors.name && (
<p className="mt-1 text-sm text-red-600">{errors.name}</p>
)}
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium">
Email
</label>
<input
id="email"
type="email"
value={formData.email}
onChange={(e) => handleInputChange('email', e.target.value)}
className={cn(
'mt-1 block w-full px-3 py-2 border rounded-md',
errors.email && 'border-red-500'
)}
/>
{errors.email && (
<p className="mt-1 text-sm text-red-600">{errors.email}</p>
)}
</div>
<div>
<label htmlFor="age" className="block text-sm font-medium">
Age
</label>
<input
id="age"
type="number"
value={formData.age}
onChange={(e) => handleInputChange('age', parseInt(e.target.value))}
className={cn(
'mt-1 block w-full px-3 py-2 border rounded-md',
errors.age && 'border-red-500'
)}
/>
{errors.age && (
<p className="mt-1 text-sm text-red-600">{errors.age}</p>
)}
</div>
<button
type="submit"
className="w-full py-2 px-4 bg-blue-600 text-white rounded-md hover:bg-blue-700"
>
Submit
</button>
</form>
)
}
Tree Shaking
FoundryKit utils supports tree shaking for optimal bundle sizes.
// Import only what you need
import { cn } from '@foundrykit/utils/cn'
import { formatDate } from '@foundrykit/utils/date'
import { debounce } from '@foundrykit/utils/function'
// Or use named imports (tree-shakable)
import { cn, formatDate, debounce } from '@foundrykit/utils'
Browser Compatibility
FoundryKit utils supports modern browsers and provides polyfills where needed:
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
For older browser support, consider using polyfills:
npm install core-js
Performance Considerations
- Tree Shaking: Import only the utilities you need
- Memoization: Use built-in memoization for expensive operations
- Debouncing: Optimize event handlers with debounce/throttle
- Bundle Size: Monitor your bundle size when adding utilities
Next Steps
- Explore utility functions reference for detailed usage
- Learn about common patterns for effective usage
- Review performance tips for optimization
- Check out best practices for optimal usage