React data table and react data grid
npm install @tracktor/react-utils

> A comprehensive collection of modern React utilities and custom hooks to accelerate your development workflow.
``bashnpm
npm install @tracktor/react-utils
π Quick Start
`typescript
import { useInputState, capitalize, phoneNumberAdapter } from '@tracktor/react-utils';function App() {
const [email, onEmailChange] = useInputState('');
const [phone, onPhoneChange] = useInputState('');
return (
);
}
`π API Documentation
$3
####
useLocalStorage(key, initialValue?, options?)
Manages data persistence in localStorage with automatic synchronization.`typescript
const [user, setUser, removeUser] = useLocalStorage('user', { name: '', email: '' });// With custom options
const [data, setData] = useLocalStorage('data', [], {
serializer: JSON.stringify,
deserializer: JSON.parse
});
`Parameters:
-
key: localStorage key
- initialValue: Initial value (optional)
- options: Serialization options (optional)Returns:
[value, setValue, removeValue]---
####
useInputState(initialValue)
Simplifies input state management with automatic event handling.`typescript
const [name, onNameChange] = useInputState('');
const [isChecked, onCheckChange] = useInputState(false);
`---
####
useDebounce(value, delayOrOptions)
Delays execution of a value to prevent excessive calls.`typescript
// Simple usage
const debouncedSearchTerm = useDebounce(searchTerm, 500);// With callback
const debouncedValue = useDebounce(inputValue, {
delay: 300,
onDebounce: (value) => console.log('Debounced:', value)
});
`---
####
useToggle(initialState?)
Manages boolean state with toggle functionality.`typescript
const [isOpen, toggle, setIsOpen] = useToggle(false);
`---
####
useWindowSize()
Tracks window dimensions in real-time.`typescript
const { width, height } = useWindowSize();return (
Size: {width}x{height}
);
`---
####
useInView(ref, options?)
Detects if an element is visible in the viewport.`typescript
const ref = useRef(null);
const isInView = useInView(ref, {
threshold: 0.5,
triggerOnce: true
});
{isInView ? 'Visible!' : 'Not visible'}
`---
####
useDocumentTitle(title)
Manages document title declaratively.`typescript
const { setTitle, title } = useDocumentTitle('My App');// Change title dynamically
setTitle('New Page');
`---
####
useEventListener(eventName, handler, element?, options?)
Adds event listeners with automatic cleanup.`typescript
const buttonRef = useRef(null);useEventListener('click', () => console.log('Clicked!'), buttonRef);
useEventListener('keydown', handleKeyDown); // window by default
`---
####
useScript(src, options?)
Loads external scripts declaratively.`typescript
const status = useScript('https://example.com/script.js', {
position: 'body-end',
enable: true
});// status: 'idle' | 'loading' | 'ready' | 'error'
`---
####
useIntersectionObserver(elementRef, options)
Advanced intersection observer hook for complex visibility detection.`typescript
const elementRef = useRef(null);
const entry = useIntersectionObserver(elementRef, {
threshold: 0.1,
freezeOnceVisible: true
});const isVisible = entry?.isIntersecting;
`---
####
useIsMounted()
Returns a function to check if component is still mounted.`typescript
const isMounted = useIsMounted();useEffect(() => {
fetchData().then(data => {
if (isMounted()) {
setData(data);
}
});
}, []);
`---
####
useEventCallback(fn)
Ensures callback stability while maintaining current references.`typescript
const handleClick = useEventCallback((id) => {
// This callback is stable but has access to current state
onItemClick(id, currentState);
});
`$3
#### Type Validation
`typescript
import { isArray, isObject, isString, isNumber, isBoolean, isFunction, isRef } from '@tracktor/react-utils';if (isArray(data)) {
// TypeScript knows data is an array
console.log(data.length);
}
if (isObject(value)) {
// TypeScript knows value is an object
console.log(Object.keys(value));
}
`#### Object Manipulation
`typescript
import { removeObjectProperty, isDeepEqualObject } from '@tracktor/react-utils';// Remove property without mutation
const newObj = removeObjectProperty(originalObj, 'propertyToRemove');
// Deep comparison of objects
const areEqual = isDeepEqualObject(obj1, obj2);
`#### String Manipulation
`typescript
import { capitalize, capitalizeWords } from '@tracktor/react-utils';capitalize('hello world'); // "Hello world"
capitalizeWords('hello world'); // "Hello World"
`#### Number Conversion
`typescript
import { toNumberOrZero } from '@tracktor/react-utils';toNumberOrZero('42'); // 42
toNumberOrZero('abc'); // 0
toNumberOrZero(null); // 0
toNumberOrZero(true); // 0 (booleans return 0)
`$3
####
phoneNumberAdapter(phoneNumber, options?)
Formats phone numbers according to international standards.`typescript
// Supported formats
phoneNumberAdapter('0123456789'); // "01 23 45 67 89" (France)
phoneNumberAdapter('441234567890'); // "1234 567 890" (UK)
phoneNumberAdapter('1234567890'); // "(123) 456-7890" (US)// With international prefix
phoneNumberAdapter('33123456789', { addPrefix: true }); // "+33 01 23 45 67 89"
// Custom separator
phoneNumberAdapter('0123456789', { separator: '-' }); // "01-23-45-67-89"
`Supported Countries:
| Code | Country | Format |
|------|---------|--------|
| 33 | France | 01 23 45 67 89 |
| 44 | United Kingdom | 1234 567 890 |
| 49 | Germany | 0151 234 56789 |
| 34 | Spain | 987 654 321 |
| 1 | United States | (123) 456-7890 |
---
####
priceAdapter(value, options?)
Formats prices according to locales and currencies.`typescript
priceAdapter(1000); // "1 000 β¬"
priceAdapter(1000.50); // "1 000,50 β¬"
priceAdapter(500, { local: 'en-US' }); // "β¬500"
priceAdapter('-'); // "-β¬"
priceAdapter(null); // "0 β¬"
`Options:
-
local: Locale string (default: 'fr-FR')
- currency: Currency code (default: 'EUR')
- style: Number format style (default: 'currency')---
####
formatCreditCardNumber(number, maxLength?)
Formats credit card numbers with proper spacing.`typescript
formatCreditCardNumber('1234567890123456'); // "1234 5678 9012 3456"
formatCreditCardNumber('1234567890123456', 15); // "1234 5678 9012 3"
formatCreditCardNumber(1234567890123456); // "1234 5678 9012 3456"
`---
####
addressToString(address)
Converts an address object to a formatted string.`typescript
const address = {
streetNumber: 82,
route: 'Chemin de cafon 2',
postalCode: '83720',
city: 'Trans en provence',
country: 'France'
};addressToString(address); // "82 Chemin de cafon 2, 83720 Trans en provence, France"
// Partial addresses work too
addressToString({ city: 'Paris', country: 'France' }); // "Paris, France"
`---
####
getInitials(name, capitalize?)
Extracts initials from a name.`typescript
// With first and last name
getInitials({ firstName: 'John', lastName: 'Doe' }); // "JD"// With full name
getInitials({ fullName: 'John Doe Smith' }); // "JD"
// With forced capitalization
getInitials({ firstName: 'john', lastName: 'doe' }, true); // "JD"
getInitials({ firstName: 'john', lastName: 'doe' }, false); // "jd"
`π¨ Usage Examples
$3
`typescript
import React from 'react';
import {
useInputState,
useToggle,
phoneNumberAdapter,
capitalize,
formatCreditCardNumber
} from '@tracktor/react-utils';function ContactForm() {
const [name, onNameChange] = useInputState('');
const [email, onEmailChange] = useInputState('');
const [phone, onPhoneChange] = useInputState('');
const [cardNumber, onCardChange] = useInputState('');
const [acceptTerms, toggleTerms] = useToggle(false);
const handleSubmit = (e) => {
e.preventDefault();
console.log({
name: capitalize(name),
email,
phone: phoneNumberAdapter(phone, { addPrefix: true }),
cardNumber: formatCreditCardNumber(cardNumber)
});
};
return (
);
}
`$3
`typescript
import React, { useEffect, useState } from 'react';
import { useDebounce, useInputState } from '@tracktor/react-utils';function SearchComponent() {
const [query, onQueryChange] = useInputState('');
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
const debouncedQuery = useDebounce(query, {
delay: 300,
onDebounce: () => setLoading(true)
});
useEffect(() => {
if (debouncedQuery) {
// Simulate API call
fetch(
/api/search?q=${debouncedQuery})
.then(res => res.json())
.then(data => {
setResults(data);
setLoading(false);
});
} else {
setResults([]);
setLoading(false);
}
}, [debouncedQuery]); return (
placeholder="Search..."
value={query}
onChange={onQueryChange}
/>
{loading && Searching...}
{results.map(item => (
- {item.title}
))}
);
}
`$3
`typescript
import React, { useRef } from 'react';
import { useInView, useIntersectionObserver } from '@tracktor/react-utils';function VisibilityExample() {
const simpleRef = useRef(null);
const advancedRef = useRef(null);
// Simple visibility detection
const isSimpleInView = useInView(simpleRef, {
threshold: 0.5,
triggerOnce: true
});
// Advanced intersection observer
const entry = useIntersectionObserver(advancedRef, {
threshold: [0, 0.25, 0.5, 0.75, 1],
rootMargin: '50px'
});
return (
{isSimpleInView ? 'β
Simple: Visible' : 'β Simple: Hidden'}
Advanced: {entry?.intersectionRatio.toFixed(2) || 0}% visible
);
}
`π§ͺ Testing
The library is fully tested with Vitest. To run tests:
`bash
Unit tests
yarn testCoverage report
yarn coverageLint code
yarn lint
`π‘οΈ TypeScript Support
All utilities and hooks are fully typed with TypeScript. Types are automatically inferred:
`typescript
const [count, setCount] = useLocalStorage('count', 0); // count is number
const [user, setUser] = useLocalStorage('user', { name: '', age: 0 }); // user is typed// Type guards work perfectly
if (isArray(data)) {
data.map(item => item); // TypeScript knows data is an array
}
if (isString(value)) {
value.toUpperCase(); // TypeScript knows value is a string
}
`π Requirements
- React β₯ 18.0.0
- React DOM β₯ 18.0.0
- TypeScript support included
π Features
- β
Fully typed with TypeScript
- β
Tree-shakeable - Import only what you need
- β
SSR compatible - Works with Next.js, Gatsby, etc.
- β
Lightweight - Minimal bundle impact
- β
Well tested - Comprehensive test suite
- β
Modern - Uses latest React patterns
- β
Performance focused - Optimized hooks and utilities
π€ Contributing
Contributions are welcome! Please check our contributing guide.
1. Fork the project
2. Create your feature branch (
git checkout -b feature/AmazingFeature)
3. Commit your changes (git commit -m 'Add some AmazingFeature')
4. Push to the branch (git push origin feature/AmazingFeature`)This project is licensed under the ISC License. See the LICENSE file for details.
- React
- React Hooks
- Utilities
- TypeScript
- Performance
- Developer Experience
- Form Handling
- State Management
- π Report a bug
- π‘ Request a feature
- π Documentation
- π¬ Discussions
We're constantly improving! Upcoming features:
- π More form utilities
- π± Mobile-specific hooks
- π¨ Animation helpers
- π Data manipulation utilities
---
Built with β€οΈ by MickaΓ«l Austoni