diff --git a/packages/docs/src/registry/items/useDateRange.json b/packages/docs/src/registry/items/useDateRange.json new file mode 100644 index 000000000..dfa5f3c0b --- /dev/null +++ b/packages/docs/src/registry/items/useDateRange.json @@ -0,0 +1,14 @@ +{ + "type": "registry:item", + "name": "useDateRange", + "title": "Date Range Hook", + "description": "Date range selection with URL synchronization and preset support. Includes common presets like last 7 days, last 30 days, and custom ranges.", + "dependencies": ["nuqs", "date-fns@^4.1.0"], + "files": [ + { + "type": "registry:file", + "path": "https://raw.githubusercontent.com/iHiteshAgrawal/nuqs-presets/a230a749daab2327dae9907f845b445a0653dc04/registry/default/useDateRange.ts", + "target": "~/hooks/nuqs-presets/useDateRange.ts" + } + ] +} diff --git a/packages/docs/src/registry/items/useDateRange.md b/packages/docs/src/registry/items/useDateRange.md new file mode 100644 index 000000000..2b4e252ef --- /dev/null +++ b/packages/docs/src/registry/items/useDateRange.md @@ -0,0 +1,99 @@ +```tsx +'use client' + +import { useDateRange } from '@/hooks/nuqs-presets/useDateRange' + +export function DateRangePicker() { + const { + startDate, // Start date + endDate, // End date + setRange, // Set both dates + setStartDate, // Set start only + setEndDate, // Set end only + clearRange, // Clear both + presets, // Quick preset functions + daysInRange, // Number of days + isValid, // Valid range (start <= end) + } = useDateRange({ + defaultPreset: 'last7days', + }) + + return ( +
+
+ + + + +
+ +
+ setStartDate(e.target.value)} + /> + to + setEndDate(e.target.value)} + /> +
+ + {isValid && ( +

{daysInRange} days selected

+ )} + + +
+ ) +} +``` + +## API Reference + +### Options + +```typescript +interface UseDateRangeOptions { + defaultStartDate?: string // ISO date string + defaultEndDate?: string // ISO date string + defaultPreset?: PresetKey // Apply preset on mount + shallow?: boolean + history?: 'push' | 'replace' + scroll?: boolean +} +``` + +### Presets + +Available preset functions: +- `presets.today()` - Today only +- `presets.yesterday()` - Yesterday only +- `presets.last7days()` - Last 7 days +- `presets.last30days()` - Last 30 days +- `presets.thisMonth()` - Current month +- `presets.lastMonth()` - Previous month + +### Return Value + +```typescript +interface UseDateRangeResult { + startDate: string | null + endDate: string | null + setStartDate: (date: string | null) => void + setEndDate: (date: string | null) => void + setRange: (start: string | null, end: string | null) => void + clearRange: () => void + presets: DateRangePresets + daysInRange: number | null // Days between dates + isValid: boolean // startDate <= endDate +} +``` + +## More Information + +- **GitHub**: [nuqs-presets](https://github.com/iHiteshAgrawal/nuqs-presets) +- **npm**: [nuqs-presets](https://www.npmjs.com/package/nuqs-presets) +- **Examples**: See the [examples directory](https://github.com/iHiteshAgrawal/nuqs-presets/tree/main/examples) diff --git a/packages/docs/src/registry/items/useFilters.json b/packages/docs/src/registry/items/useFilters.json new file mode 100644 index 000000000..bcf7cb7cb --- /dev/null +++ b/packages/docs/src/registry/items/useFilters.json @@ -0,0 +1,14 @@ +{ + "type": "registry:item", + "name": "useFilters", + "title": "Filters Hook", + "description": "Type-safe multi-filter state management with URL synchronization. Uses nuqs parsers for strong typing and validation.", + "dependencies": ["nuqs"], + "files": [ + { + "type": "registry:file", + "path": "https://raw.githubusercontent.com/iHiteshAgrawal/nuqs-presets/a230a749daab2327dae9907f845b445a0653dc04/registry/default/useFilters.ts", + "target": "~/hooks/nuqs-presets/useFilters.ts" + } + ] +} diff --git a/packages/docs/src/registry/items/useFilters.md b/packages/docs/src/registry/items/useFilters.md new file mode 100644 index 000000000..e404611a9 --- /dev/null +++ b/packages/docs/src/registry/items/useFilters.md @@ -0,0 +1,97 @@ +```tsx +'use client' + +import { useFilters } from '@/hooks/nuqs-presets/useFilters' +import { parseAsString, parseAsFloat, parseAsBoolean } from 'nuqs' + +const filterParsers = { + category: parseAsString, + minPrice: parseAsFloat, + maxPrice: parseAsFloat, + inStock: parseAsBoolean, +} + +export function FilterPanel() { + const { + filters, // Current filters (type-safe) + setFilter, // Set single filter + setFilters, // Set multiple filters + clearFilters, // Clear all filters + clearFilter, // Clear single filter + hasFilters, // Any filters active? + } = useFilters({ + parsers: filterParsers, + }) + + // filters.category is string | null + // filters.minPrice is number | null + // filters.inStock is boolean | null + + return ( +
+ + + setFilter('minPrice', e.target.value ? Number(e.target.value) : null)} + /> + + + + {hasFilters && ( + + )} +
+ ) +} +``` + +## API Reference + +### Options + +```typescript +interface UseFiltersOptions> { + parsers: T // nuqs parser map + shallow?: boolean + history?: 'push' | 'replace' + scroll?: boolean +} +``` + +### Return Value + +```typescript +interface UseFiltersResult { + filters: ParsedFilters // Current filters (type-safe) + setFilter: (key: K, value: T[K]) => void + setFilters: (filters: Partial>) => void + clearFilter: (key: keyof T) => void + clearFilters: () => void + hasFilters: boolean // Any active filters? +} +``` + +## More Information + +- **GitHub**: [nuqs-presets](https://github.com/iHiteshAgrawal/nuqs-presets) +- **npm**: [nuqs-presets](https://www.npmjs.com/package/nuqs-presets) +- **Examples**: See the [examples directory](https://github.com/iHiteshAgrawal/nuqs-presets/tree/main/examples) diff --git a/packages/docs/src/registry/items/useMultiSelect.json b/packages/docs/src/registry/items/useMultiSelect.json new file mode 100644 index 000000000..03592301c --- /dev/null +++ b/packages/docs/src/registry/items/useMultiSelect.json @@ -0,0 +1,14 @@ +{ + "type": "registry:item", + "name": "useMultiSelect", + "title": "Multi-Select Hook", + "description": "Array-based multi-selection state management with URL synchronization. Supports toggle, select all, and deselect all operations.", + "dependencies": ["nuqs"], + "files": [ + { + "type": "registry:file", + "path": "https://raw.githubusercontent.com/iHiteshAgrawal/nuqs-presets/a230a749daab2327dae9907f845b445a0653dc04/registry/default/useMultiSelect.ts", + "target": "~/hooks/nuqs-presets/useMultiSelect.ts" + } + ] +} diff --git a/packages/docs/src/registry/items/useMultiSelect.md b/packages/docs/src/registry/items/useMultiSelect.md new file mode 100644 index 000000000..cb68443c1 --- /dev/null +++ b/packages/docs/src/registry/items/useMultiSelect.md @@ -0,0 +1,82 @@ +```tsx +'use client' + +import { useMultiSelect } from '@/hooks/nuqs-presets/useMultiSelect' + +const ITEMS = ['item1', 'item2', 'item3', 'item4'] + +export function MultiSelectList() { + const { + selected, // Selected item IDs + toggle, // Toggle single item + selectAll, // Select all items + deselectAll, // Deselect all + isSelected, // Check if item selected + selectCount, // Number selected + } = useMultiSelect({ + allItems: ITEMS, + }) + + return ( +
+
+ + + {selectCount} selected +
+ +
    + {ITEMS.map(item => ( +
  • + +
  • + ))} +
+
+ ) +} +``` + +## API Reference + +### Options + +```typescript +interface UseMultiSelectOptions { + allItems?: readonly T[] // All available items + defaultSelected?: T[] // Initially selected + shallow?: boolean + history?: 'push' | 'replace' + scroll?: boolean +} +``` + +### Return Value + +```typescript +interface UseMultiSelectResult { + selected: T[] // Selected items + toggle: (item: T) => void // Toggle selection + select: (item: T) => void // Add to selection + deselect: (item: T) => void // Remove from selection + selectAll: () => void // Select all items + deselectAll: () => void // Clear selection + isSelected: (item: T) => boolean // Check if selected + selectCount: number // Number of selected items + isAllSelected: boolean // All items selected + isNoneSelected: boolean // No items selected +} +``` + +## More Information + +- **GitHub**: [nuqs-presets](https://github.com/iHiteshAgrawal/nuqs-presets) +- **npm**: [nuqs-presets](https://www.npmjs.com/package/nuqs-presets) +- **Examples**: See the [examples directory](https://github.com/iHiteshAgrawal/nuqs-presets/tree/main/examples) diff --git a/packages/docs/src/registry/items/usePagination.json b/packages/docs/src/registry/items/usePagination.json new file mode 100644 index 000000000..affed74a4 --- /dev/null +++ b/packages/docs/src/registry/items/usePagination.json @@ -0,0 +1,14 @@ +{ + "type": "registry:item", + "name": "usePagination", + "title": "Pagination Hook", + "description": "Complete pagination state management with URL synchronization. Handles page navigation, page size control, and edge cases.", + "dependencies": ["nuqs"], + "files": [ + { + "type": "registry:file", + "path": "https://raw.githubusercontent.com/iHiteshAgrawal/nuqs-presets/a230a749daab2327dae9907f845b445a0653dc04/registry/default/usePagination.ts", + "target": "~/hooks/nuqs-presets/usePagination.ts" + } + ] +} diff --git a/packages/docs/src/registry/items/usePagination.md b/packages/docs/src/registry/items/usePagination.md new file mode 100644 index 000000000..6b8e702ae --- /dev/null +++ b/packages/docs/src/registry/items/usePagination.md @@ -0,0 +1,86 @@ +```tsx +'use client' + +import { usePagination } from '@/hooks/nuqs-presets/usePagination' + +export function ProductList() { + const { + page, // Current page (1-indexed) + pageSize, // Items per page + totalPages, // Computed total pages + hasNextPage, // Can go forward + hasPrevPage, // Can go back + nextPage, // Go to next page + prevPage, // Go to previous page + goToPage, // Go to specific page + setPageSize, // Change page size + } = usePagination({ + defaultPageSize: 10, + totalItems: 1000, + }) + + return ( +
+
+ {/* Your paginated content */} + Page {page} of {totalPages} +
+ +
+ + Page {page} + +
+ + +
+ ) +} +``` + +## API Reference + +### Options + +```typescript +interface UsePaginationOptions { + defaultPage?: number // Default: 1 + defaultPageSize?: number // Default: 10 + totalItems?: number // For computing totalPages + shallow?: boolean // nuqs shallow option + history?: 'push' | 'replace' // nuqs history option + scroll?: boolean // nuqs scroll option +} +``` + +### Return Value + +```typescript +interface UsePaginationResult { + page: number // Current page + pageSize: number // Items per page + totalPages: number | undefined // Computed if totalItems provided + hasNextPage: boolean // Can navigate forward + hasPrevPage: boolean // Can navigate backward + nextPage: () => void // Go to next page + prevPage: () => void // Go to previous page + goToPage: (page: number) => void // Go to specific page + setPageSize: (size: number) => void // Change page size (resets to page 1) + goToFirstPage: () => void // Jump to first page + goToLastPage: () => void // Jump to last page (requires totalPages) +} +``` + +## More Information + +- **GitHub**: [nuqs-presets](https://github.com/iHiteshAgrawal/nuqs-presets) +- **npm**: [nuqs-presets](https://www.npmjs.com/package/nuqs-presets) +- **Examples**: See the [examples directory](https://github.com/iHiteshAgrawal/nuqs-presets/tree/main/examples) diff --git a/packages/docs/src/registry/items/useSearch.json b/packages/docs/src/registry/items/useSearch.json new file mode 100644 index 000000000..8263ac8d2 --- /dev/null +++ b/packages/docs/src/registry/items/useSearch.json @@ -0,0 +1,14 @@ +{ + "type": "registry:item", + "name": "useSearch", + "title": "Search Hook", + "description": "Debounced search state management with URL synchronization. Includes minimum length validation and debounce control.", + "dependencies": ["nuqs"], + "files": [ + { + "type": "registry:file", + "path": "https://raw.githubusercontent.com/iHiteshAgrawal/nuqs-presets/a230a749daab2327dae9907f845b445a0653dc04/registry/default/useSearch.ts", + "target": "~/hooks/nuqs-presets/useSearch.ts" + } + ] +} diff --git a/packages/docs/src/registry/items/useSearch.md b/packages/docs/src/registry/items/useSearch.md new file mode 100644 index 000000000..cfa861fa0 --- /dev/null +++ b/packages/docs/src/registry/items/useSearch.md @@ -0,0 +1,71 @@ +```tsx +'use client' + +import { useSearch } from '@/hooks/nuqs-presets/useSearch' + +export function SearchBar() { + const { + query, // Current search query + debouncedQuery, // Debounced value for API calls + setQuery, // Update search + isDebouncing, // Debounce in progress + clearQuery, // Clear search + } = useSearch({ + debounce: 300, // ms to wait + minLength: 2, // minimum chars + trim: true, // auto-trim whitespace + }) + + // Use debouncedQuery for API calls + const { data } = useQuery({ + queryKey: ['products', debouncedQuery], + queryFn: () => fetchProducts(debouncedQuery), + }) + + return ( +
+ setQuery(e.target.value)} + placeholder="Search..." + /> + {isDebouncing && Searching...} +
+ ) +} +``` + +## API Reference + +### Options + +```typescript +interface UseSearchOptions { + defaultQuery?: string // Default: '' + debounce?: number // Default: 300ms + minLength?: number // Default: 0 (no minimum) + trim?: boolean // Default: true + shallow?: boolean // nuqs shallow option + history?: 'push' | 'replace' + scroll?: boolean +} +``` + +### Return Value + +```typescript +interface UseSearchResult { + query: string // Current query (immediate) + debouncedQuery: string // Debounced query (for API calls) + setQuery: (query: string) => void // Update query + clearQuery: () => void // Clear search + isDebouncing: boolean // Debounce in progress +} +``` + +## More Information + +- **GitHub**: [nuqs-presets](https://github.com/iHiteshAgrawal/nuqs-presets) +- **npm**: [nuqs-presets](https://www.npmjs.com/package/nuqs-presets) +- **Examples**: See the [examples directory](https://github.com/iHiteshAgrawal/nuqs-presets/tree/main/examples) diff --git a/packages/docs/src/registry/items/useSorting.json b/packages/docs/src/registry/items/useSorting.json new file mode 100644 index 000000000..860133390 --- /dev/null +++ b/packages/docs/src/registry/items/useSorting.json @@ -0,0 +1,14 @@ +{ + "type": "registry:item", + "name": "useSorting", + "title": "Sorting Hook", + "description": "Multi-column sorting state management with URL synchronization. Supports ascending, descending, and null states with smart toggling.", + "dependencies": ["nuqs"], + "files": [ + { + "type": "registry:file", + "path": "https://raw.githubusercontent.com/iHiteshAgrawal/nuqs-presets/a230a749daab2327dae9907f845b445a0653dc04/registry/default/useSorting.ts", + "target": "~/hooks/nuqs-presets/useSorting.ts" + } + ] +} diff --git a/packages/docs/src/registry/items/useSorting.md b/packages/docs/src/registry/items/useSorting.md new file mode 100644 index 000000000..c05abdc75 --- /dev/null +++ b/packages/docs/src/registry/items/useSorting.md @@ -0,0 +1,72 @@ +```tsx +'use client' + +import { useSorting } from '@/hooks/nuqs-presets/useSorting' + +export function DataTable() { + const { + sortBy, // Current sort column + sortOrder, // 'asc' | 'desc' | null + toggleSort, // Toggle column sort + isSortedBy, // Check if column is sorted + clearSort, // Clear all sorting + } = useSorting({ + columns: ['name', 'date', 'price'] as const, + defaultColumn: 'name', + defaultOrder: 'asc', + }) + + return ( + + + + + + + + + {/* Table body with sorted data */} +
toggleSort('name')}> + Name {isSortedBy('name') && (sortOrder === 'asc' ? '↑' : '↓')} + toggleSort('price')}> + Price {isSortedBy('price') && (sortOrder === 'asc' ? '↑' : '↓')} + toggleSort('date')}> + Date {isSortedBy('date') && (sortOrder === 'asc' ? '↑' : '↓')} +
+ ) +} +``` + +## API Reference + +### Options + +```typescript +interface UseSortingOptions { + columns: T // Available columns + defaultColumn?: T[number] // Initial sort column + defaultOrder?: 'asc' | 'desc' // Initial order + shallow?: boolean + history?: 'push' | 'replace' + scroll?: boolean +} +``` + +### Return Value + +```typescript +interface UseSortingResult { + sortBy: T | null // Current column + sortOrder: 'asc' | 'desc' | null // Current order + toggleSort: (column: T) => void // Toggle column (null→asc→desc→null) + setSorting: (column: T | null, order: 'asc' | 'desc' | null) => void + isSortedBy: (column: T) => boolean // Check if column is active + clearSort: () => void // Clear sorting +} +``` + +## More Information + +- **GitHub**: [nuqs-presets](https://github.com/iHiteshAgrawal/nuqs-presets) +- **npm**: [nuqs-presets](https://www.npmjs.com/package/nuqs-presets) +- **Examples**: See the [examples directory](https://github.com/iHiteshAgrawal/nuqs-presets/tree/main/examples) diff --git a/packages/docs/src/registry/items/useTabs.json b/packages/docs/src/registry/items/useTabs.json new file mode 100644 index 000000000..7cd3b3ae2 --- /dev/null +++ b/packages/docs/src/registry/items/useTabs.json @@ -0,0 +1,14 @@ +{ + "type": "registry:item", + "name": "useTabs", + "title": "Tabs Hook", + "description": "Type-safe tab navigation with URL synchronization. Provides strongly-typed tab values and active state checking.", + "dependencies": ["nuqs"], + "files": [ + { + "type": "registry:file", + "path": "https://raw.githubusercontent.com/iHiteshAgrawal/nuqs-presets/a230a749daab2327dae9907f845b445a0653dc04/registry/default/useTabs.ts", + "target": "~/hooks/nuqs-presets/useTabs.ts" + } + ] +} diff --git a/packages/docs/src/registry/items/useTabs.md b/packages/docs/src/registry/items/useTabs.md new file mode 100644 index 000000000..c0c42df61 --- /dev/null +++ b/packages/docs/src/registry/items/useTabs.md @@ -0,0 +1,76 @@ +```tsx +'use client' + +import { useTabs } from '@/hooks/nuqs-presets/useTabs' + +export function TabsExample() { + const { + activeTab, // Current tab (type-safe) + setTab, // Change tab + isActive, // Check if tab is active + } = useTabs(['overview', 'analytics', 'settings'] as const) + + // activeTab is typed as 'overview' | 'analytics' | 'settings' + + return ( +
+
+ + + +
+ +
+ {activeTab === 'overview' && } + {activeTab === 'analytics' && } + {activeTab === 'settings' && } +
+
+ ) +} +``` + +## API Reference + +### Options + +```typescript +interface UseTabsOptions { + tabs: T // Available tabs + defaultTab?: T[number] // Initial tab + shallow?: boolean + history?: 'push' | 'replace' + scroll?: boolean +} +``` + +### Return Value + +```typescript +interface UseTabsResult { + activeTab: T // Current tab (type-safe) + setTab: (tab: T) => void // Change tab + isActive: (tab: T) => boolean // Check if tab is active +} +``` + +## More Information + +- **GitHub**: [nuqs-presets](https://github.com/iHiteshAgrawal/nuqs-presets) +- **npm**: [nuqs-presets](https://www.npmjs.com/package/nuqs-presets) +- **Examples**: See the [examples directory](https://github.com/iHiteshAgrawal/nuqs-presets/tree/main/examples)