Initial commit

This commit is contained in:
Igor Martyniuk
2026-06-25 15:53:49 +03:00
commit 1bb0b7e68a
1517 changed files with 218469 additions and 0 deletions
@@ -0,0 +1,61 @@
# useDebounceSearch
Controls a search input with debouncing and a minimum character threshold. Only fires the `onTimeOut` callback after the user stops typing and the query meets the minimum length.
## Signature
```ts
function useDebounceSearch(params: UseDebounceSearchParams): DebounceSearchController;
```
### Params
```ts
type UseDebounceSearchParams = {
onTimeOut: (query: string) => void;
minQueryNumber?: number;
initialQuery?: string | null;
delay?: number;
};
```
| Param | Type | Default | Description |
| ---------------- | ------------------------- | ------- | ------------------------------------------------------------ |
| `onTimeOut` | `(query: string) => void` | — | Called with the current query after `delay` ms of inactivity |
| `minQueryNumber` | `number` | `3` | Minimum characters required before `onTimeOut` is invoked |
| `initialQuery` | `string \| null` | `''` | Initial value of the controlled input |
| `delay` | `number` | `800` | Debounce delay in milliseconds |
### Returns
```ts
type DebounceSearchController = {
query: string;
handleChange: (value: string) => void;
};
```
| Property | Type | Description |
| -------------- | ------------------------- | -------------------------------------- |
| `query` | `string` | Current value of the search input |
| `handleChange` | `(value: string) => void` | Pass to the input's `onChange` handler |
## Usage
```tsx
function SearchBox() {
const { query, handleChange } = useDebounceSearch({
onTimeOut: (q) => fetchResults(q),
minQueryNumber: 2,
delay: 500,
});
return <input value={query} onChange={(e) => handleChange(e.target.value)} placeholder="Search…" />;
}
```
## Notes
- Queries shorter than `minQueryNumber` (but not empty) cancel any pending debounced call.
- Uses `throttle-debounce` under the hood via a stable `useRef` to avoid resetting the timer on each render.
- Client-only (`'use client'`).
@@ -0,0 +1 @@
export * from './useDebounceSearch';
@@ -0,0 +1,38 @@
'use client';
import { useRef, useState } from 'react';
import { debounce } from 'throttle-debounce';
export type UseDebounceSearchParams = {
onTimeOut: (query: string) => void;
minQueryNumber?: number;
initialQuery?: string | null;
delay?: number;
};
export type DebounceSearchController = {
query: string;
handleChange: (value: string) => void;
};
export const useDebounceSearch = (params: UseDebounceSearchParams): DebounceSearchController => {
const { onTimeOut, minQueryNumber = 3, delay = 800, initialQuery } = params;
const [query, setQuery] = useState(initialQuery ?? '');
const throttled = useRef(debounce(delay, (callback: () => void) => callback()));
const bind = (value: string) => throttled.current(onTimeOut.bind(null, value));
const unbind = () => throttled.current(() => {});
const handleChange = (value: string) => {
setQuery(value);
if (value.length < minQueryNumber && value.length !== 0) {
return unbind();
}
bind(value);
};
return { query, handleChange };
};