A comprehensive collection of 75+ React hooks for state and UI management including storage, events, browser APIs, and performance optimizations
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Advanced and specialized hooks for unique UI patterns including color picker integration, file dialogs, selection management, and radial interactions.
EyeDropper API integration for color picking from the screen.
/**
* EyeDropper API integration for color picking
* @returns Object with support status and open function
*/
function useEyeDropper(): UseEyeDropperReturnValue;
interface EyeDropperOpenOptions {
signal?: AbortSignal;
}
interface EyeDropperOpenReturnType {
sRGBHex: string;
}
interface UseEyeDropperReturnValue {
supported: boolean;
open: (options?: EyeDropperOpenOptions) => Promise<EyeDropperOpenReturnType>;
}Usage Examples:
import { useEyeDropper } from "@mantine/hooks";
function ColorPicker() {
const [color, setColor] = useState('#000000');
const eyeDropper = useEyeDropper();
const pickColor = async () => {
if (!eyeDropper.supported) {
alert('EyeDropper API not supported');
return;
}
try {
const result = await eyeDropper.open();
setColor(result.sRGBHex);
} catch (error) {
console.log('Color picking cancelled');
}
};
return (
<div>
<div style={{ width: 50, height: 50, background: color }} />
<button onClick={pickColor} disabled={!eyeDropper.supported}>
Pick Color from Screen
</button>
</div>
);
}File input dialog with configurable options and callback handling.
/**
* File input dialog with options
* @param options - Configuration for file selection
* @returns Object with open and reset functions
*/
function useFileDialog(options: UseFileDialogOptions): UseFileDialogReturnValue;
interface UseFileDialogOptions {
multiple?: boolean;
accept?: string;
capture?: boolean | 'user' | 'environment';
onFiles: (files: FileList | null) => void;
}
interface UseFileDialogReturnValue {
open: () => void;
reset: () => void;
}Usage Examples:
import { useFileDialog } from "@mantine/hooks";
function ImageUploader() {
const [images, setImages] = useState<File[]>([]);
const fileDialog = useFileDialog({
multiple: true,
accept: 'image/*',
onFiles: (files) => {
if (files) {
setImages(Array.from(files));
}
}
});
return (
<div>
<button onClick={fileDialog.open}>
Select Images
</button>
<button onClick={fileDialog.reset}>
Reset
</button>
<div>
{images.map((file, index) => (
<div key={index}>{file.name}</div>
))}
</div>
</div>
);
}
// Camera capture
function CameraCapture() {
const cameraDialog = useFileDialog({
accept: 'image/*',
capture: 'environment', // Use back camera
onFiles: (files) => {
if (files && files[0]) {
handlePhotoCapture(files[0]);
}
}
});
return <button onClick={cameraDialog.open}>Take Photo</button>;
}Multi-select state management with comprehensive selection handlers.
/**
* Multi-select state management
* @param items - Array of items to manage selection for
* @param input - Configuration for selection behavior
* @returns Object with selected items, handlers, and utilities
*/
function useSelection<T>(
items: T[],
input?: UseSelectionInput<T>
): UseSelectionReturnValue<T>;
interface UseSelectionInput<T> {
multiple?: boolean;
value?: T | T[];
onSelectionChange?: (value: T | T[]) => void;
}
interface UseSelectionHandlers<T> {
select: (item: T) => void;
deselect: (item: T) => void;
toggle: (item: T) => void;
selectAll: () => void;
deselectAll: () => void;
setSelection: (items: T[]) => void;
}
interface UseSelectionReturnValue<T> {
selected: T[];
handlers: UseSelectionHandlers<T>;
isSelected: (item: T) => boolean;
}Usage Examples:
import { useSelection } from "@mantine/hooks";
function TodoList() {
const todos = [
{ id: 1, text: 'Learn React' },
{ id: 2, text: 'Build app' },
{ id: 3, text: 'Deploy' }
];
const selection = useSelection(todos, {
multiple: true,
onSelectionChange: (selected) => {
console.log('Selected todos:', selected);
}
});
const deleteSelected = () => {
// Delete selected todos
const selectedIds = selection.selected.map(todo => todo.id);
deleteTodos(selectedIds);
selection.deselectAll();
};
return (
<div>
<div>
<button onClick={selection.handlers.selectAll}>
Select All
</button>
<button onClick={selection.handlers.deselectAll}>
Deselect All
</button>
<button onClick={deleteSelected} disabled={selection.selected.length === 0}>
Delete Selected ({selection.selected.length})
</button>
</div>
{todos.map(todo => (
<div key={todo.id}>
<input
type="checkbox"
checked={selection.isSelected(todo)}
onChange={() => selection.handlers.toggle(todo)}
/>
{todo.text}
</div>
))}
</div>
);
}Circular/radial mouse interactions for knobs, dials, and circular controls.
/**
* Circular/radial mouse interactions
* @param options - Configuration for radial movement
* @returns Object with ref callback
*/
function useRadialMove<T extends HTMLElement = any>(
options?: UseRadialMoveOptions
): UseRadialMoveReturnValue<T>;
/**
* Normalize radial value to 0-1 range
* @param value - Value to normalize
* @returns Normalized value
*/
function normalizeRadialValue(value: number): number;
interface UseRadialMoveOptions {
onValueChange?: (value: number) => void;
onScrubStart?: () => void;
onScrubEnd?: () => void;
step?: number;
max?: number;
min?: number;
}
interface UseRadialMoveReturnValue<T extends HTMLElement = any> {
ref: React.RefCallback<T | null>;
}Usage Examples:
import { useRadialMove, normalizeRadialValue } from "@mantine/hooks";
function VolumeKnob() {
const [volume, setVolume] = useState(0.5);
const { ref } = useRadialMove({
onValueChange: (value) => {
const normalized = normalizeRadialValue(value);
setVolume(normalized);
},
min: 0,
max: 1,
step: 0.01
});
return (
<div
ref={ref}
style={{
width: 100,
height: 100,
borderRadius: '50%',
border: '2px solid #ccc',
position: 'relative',
cursor: 'pointer'
}}
>
<div
style={{
position: 'absolute',
top: '50%',
left: '50%',
width: 4,
height: 40,
background: '#000',
transformOrigin: 'center bottom',
transform: `translate(-50%, -100%) rotate(${volume * 270 - 135}deg)`
}}
/>
<div>Volume: {Math.round(volume * 100)}%</div>
</div>
);
}Track mouse position relative to an element.
/**
* Track mouse position relative to element
* @returns Object with ref and mouse coordinates
*/
function useMouse<T extends HTMLElement = any>(): {
ref: React.RefCallback<T | null>;
x: number;
y: number;
};Track current text selection in the document.
/**
* Track current text selection
* @returns Current Selection object or null
*/
function useTextSelection(): Selection | null;Return focus to previously focused element after modal/dialog closes.
/**
* Return focus to previous element
* @param options - Configuration for focus return
* @returns Object with returnFocus function
*/
function useFocusReturn(options?: UseFocusReturnOptions): UseFocusReturnReturnValue;
interface UseFocusReturnOptions {
opened: boolean;
shouldReturnFocus?: boolean;
}
interface UseFocusReturnReturnValue {
returnFocus: () => void;
}Development logging utility for debugging hook state changes.
/**
* Development logging utility
* @param name - Name for the logger
* @param props - Object to log when it changes
*/
function useLogger(name: string, props: Record<string, any>): void;Usage Examples:
import { useLogger } from "@mantine/hooks";
function DebugComponent({ userId, settings }: Props) {
const [count, setCount] = useState(0);
// Log prop and state changes in development
useLogger('DebugComponent', { userId, settings, count });
return (
<div>
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
</div>
);
}import { useFileDialog, useClipboard } from "@mantine/hooks";
function AdvancedFileUploader() {
const [files, setFiles] = useState<File[]>([]);
const [uploadProgress, setUploadProgress] = useState<Record<string, number>>({});
const clipboard = useClipboard();
const imageDialog = useFileDialog({
multiple: true,
accept: 'image/*',
onFiles: (fileList) => {
if (fileList) {
const newFiles = Array.from(fileList);
setFiles(prev => [...prev, ...newFiles]);
// Start upload for each file
newFiles.forEach(uploadFile);
}
}
});
const uploadFile = async (file: File) => {
const formData = new FormData();
formData.append('file', file);
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
if (response.ok) {
const result = await response.json();
clipboard.copy(result.url);
}
} catch (error) {
console.error('Upload failed:', error);
}
};
return (
<div>
<button onClick={imageDialog.open}>
Select Images
</button>
<div>
{files.map((file, index) => (
<div key={index}>
{file.name}
{uploadProgress[file.name] && (
<div>Progress: {uploadProgress[file.name]}%</div>
)}
</div>
))}
</div>
</div>
);
}