@mohasinac/react 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +408 -2
- package/dist/index.d.cts +270 -2
- package/dist/index.d.ts +270 -2
- package/dist/index.js +403 -1
- package/package.json +3 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { RefObject } from 'react';
|
|
1
|
+
import { RefObject, Dispatch, SetStateAction } from 'react';
|
|
2
|
+
import * as next_navigation from 'next/navigation';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* useMediaQuery Hook
|
|
@@ -363,4 +364,271 @@ interface UseCameraReturn {
|
|
|
363
364
|
*/
|
|
364
365
|
declare function useCamera(): UseCameraReturn;
|
|
365
366
|
|
|
366
|
-
|
|
367
|
+
interface UseBulkSelectionOptions<T> {
|
|
368
|
+
/** The current page / list of items being displayed. */
|
|
369
|
+
items: T[];
|
|
370
|
+
/** Extract a stable unique key from each item (e.g. `item => item.id`). */
|
|
371
|
+
keyExtractor: (item: T) => string;
|
|
372
|
+
/**
|
|
373
|
+
* Maximum number of IDs that can be selected at once.
|
|
374
|
+
* @default 100
|
|
375
|
+
*/
|
|
376
|
+
maxSelection?: number;
|
|
377
|
+
}
|
|
378
|
+
interface UseBulkSelectionReturn {
|
|
379
|
+
selectedIds: string[];
|
|
380
|
+
selectedCount: number;
|
|
381
|
+
/** Returns `true` if the given ID is currently selected. */
|
|
382
|
+
isSelected: (id: string) => boolean;
|
|
383
|
+
/** `true` when every item on the current page is selected. */
|
|
384
|
+
isAllSelected: boolean;
|
|
385
|
+
/**
|
|
386
|
+
* `true` when some — but not all — items are selected.
|
|
387
|
+
* Use to set the indeterminate state on the header checkbox.
|
|
388
|
+
*/
|
|
389
|
+
isIndeterminate: boolean;
|
|
390
|
+
/** Toggle one item in or out of the selection. Respects `maxSelection`. */
|
|
391
|
+
toggle: (id: string) => void;
|
|
392
|
+
/**
|
|
393
|
+
* Select all items on the current page (up to `maxSelection`),
|
|
394
|
+
* or deselect all if every item is already selected.
|
|
395
|
+
*/
|
|
396
|
+
toggleAll: () => void;
|
|
397
|
+
/** Deselect everything. Call this after a bulk action completes. */
|
|
398
|
+
clearSelection: () => void;
|
|
399
|
+
/**
|
|
400
|
+
* Direct state setter — pass straight to a table's `onSelectionChange`
|
|
401
|
+
* or use when you need to replace the entire selection programmatically.
|
|
402
|
+
*/
|
|
403
|
+
setSelectedIds: Dispatch<SetStateAction<string[]>>;
|
|
404
|
+
}
|
|
405
|
+
declare function useBulkSelection<T>({ items, keyExtractor, maxSelection, }: UseBulkSelectionOptions<T>): UseBulkSelectionReturn;
|
|
406
|
+
|
|
407
|
+
interface UseUrlTableOptions {
|
|
408
|
+
/** Default param values used when a param is absent from the URL */
|
|
409
|
+
defaults?: Record<string, string>;
|
|
410
|
+
}
|
|
411
|
+
declare function useUrlTable(options?: UseUrlTableOptions): {
|
|
412
|
+
params: next_navigation.ReadonlyURLSearchParams;
|
|
413
|
+
get: (key: string) => string;
|
|
414
|
+
getNumber: (key: string, fallback?: number) => number;
|
|
415
|
+
set: (key: string, value: string) => void;
|
|
416
|
+
setMany: (updates: Record<string, string>) => void;
|
|
417
|
+
clear: (keys?: string[]) => void;
|
|
418
|
+
setPage: (page: number) => void;
|
|
419
|
+
setPageSize: (size: number) => void;
|
|
420
|
+
setSort: (sort: string) => void;
|
|
421
|
+
buildSieveParams: (sieveFilters: string) => string;
|
|
422
|
+
buildSearchParams: () => string;
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
type UrlTable$1 = ReturnType<typeof useUrlTable>;
|
|
426
|
+
interface UsePendingFiltersOptions {
|
|
427
|
+
/** The page's useUrlTable instance */
|
|
428
|
+
table: UrlTable$1;
|
|
429
|
+
/** URL param keys to manage (e.g. ['status', 'category', 'role']) */
|
|
430
|
+
keys: string[];
|
|
431
|
+
}
|
|
432
|
+
interface UsePendingFiltersReturn {
|
|
433
|
+
/** Current uncommitted selections per key (string[] per key) */
|
|
434
|
+
pending: Record<string, string[]>;
|
|
435
|
+
/** Values currently in the URL (committed) per key */
|
|
436
|
+
applied: Record<string, string[]>;
|
|
437
|
+
/** true when pending differs from applied */
|
|
438
|
+
isDirty: boolean;
|
|
439
|
+
/** Total number of selected values across all pending keys */
|
|
440
|
+
pendingCount: number;
|
|
441
|
+
/** Total number of selected values in the URL (for badge display) */
|
|
442
|
+
appliedCount: number;
|
|
443
|
+
/** Update one key in pending state (does NOT write to URL) */
|
|
444
|
+
set: (key: string, values: string[]) => void;
|
|
445
|
+
/** Write all pending keys to the URL (resets page to 1) */
|
|
446
|
+
apply: () => void;
|
|
447
|
+
/** Discard pending, revert to applied (URL) state */
|
|
448
|
+
reset: () => void;
|
|
449
|
+
/** Clear all keys in both pending state and the URL */
|
|
450
|
+
clear: () => void;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* usePendingFilters
|
|
454
|
+
*
|
|
455
|
+
* Manages local (uncommitted) filter state for a FilterDrawer or any deferred
|
|
456
|
+
* filter panel. Values are only written to the URL when `apply()` is called.
|
|
457
|
+
*
|
|
458
|
+
* Initialised from the current URL params on mount, so opening a drawer
|
|
459
|
+
* pre-fills any already-applied filters.
|
|
460
|
+
*
|
|
461
|
+
* @example
|
|
462
|
+
* ```ts
|
|
463
|
+
* const table = useUrlTable({ defaults: { pageSize: '25' } });
|
|
464
|
+
* const filters = usePendingFilters({ table, keys: ['status', 'category'] });
|
|
465
|
+
*
|
|
466
|
+
* <FilterDrawer
|
|
467
|
+
* onApply={() => { filters.apply(); setDrawerOpen(false); }}
|
|
468
|
+
* onReset={() => filters.clear()}
|
|
469
|
+
* activeCount={filters.appliedCount}
|
|
470
|
+
* >
|
|
471
|
+
* <FilterFacetSection
|
|
472
|
+
* title="Status"
|
|
473
|
+
* options={STATUS_OPTIONS}
|
|
474
|
+
* selected={filters.pending['status'] ?? []}
|
|
475
|
+
* onChange={(v) => filters.set('status', v)}
|
|
476
|
+
* />
|
|
477
|
+
* </FilterDrawer>
|
|
478
|
+
* ```
|
|
479
|
+
*/
|
|
480
|
+
declare function usePendingFilters({ table, keys, }: UsePendingFiltersOptions): UsePendingFiltersReturn;
|
|
481
|
+
|
|
482
|
+
type UrlTable = ReturnType<typeof useUrlTable>;
|
|
483
|
+
/**
|
|
484
|
+
* Minimal UrlTable-compatible interface consumed by *Filters components.
|
|
485
|
+
*/
|
|
486
|
+
interface PendingTable {
|
|
487
|
+
get: (key: string) => string;
|
|
488
|
+
set: (key: string, value: string) => void;
|
|
489
|
+
setMany: (updates: Record<string, string>) => void;
|
|
490
|
+
}
|
|
491
|
+
interface UsePendingTableReturn {
|
|
492
|
+
/** Drop-in UrlTable replacement that reads/writes to pending state */
|
|
493
|
+
pendingTable: PendingTable;
|
|
494
|
+
/** Count of applied (URL) filter values — use for the filter badge */
|
|
495
|
+
filterActiveCount: number;
|
|
496
|
+
/** Commit all pending changes to the URL (resets page to 1) */
|
|
497
|
+
onFilterApply: () => void;
|
|
498
|
+
/** Clear all filter keys from pending state and URL */
|
|
499
|
+
onFilterClear: () => void;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* usePendingTable
|
|
503
|
+
*
|
|
504
|
+
* A thin wrapper around `usePendingFilters` that exposes a `pendingTable`
|
|
505
|
+
* object matching the `UrlTable` interface (`get`, `set`, `setMany`).
|
|
506
|
+
*
|
|
507
|
+
* Drop this into any listing view to replace the per-filter `useState` +
|
|
508
|
+
* `handleFilterApply` + `handleFilterClear` boilerplate.
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* ```tsx
|
|
512
|
+
* const { pendingTable, filterActiveCount, onFilterApply, onFilterClear } =
|
|
513
|
+
* usePendingTable(table, ['status', 'category', 'minPrice', 'maxPrice']);
|
|
514
|
+
*
|
|
515
|
+
* // Pass pendingTable directly to any *Filters component:
|
|
516
|
+
* filterContent={<ProductFilters table={pendingTable} showStatus />}
|
|
517
|
+
* filterActiveCount={filterActiveCount}
|
|
518
|
+
* onFilterApply={onFilterApply}
|
|
519
|
+
* onFilterClear={onFilterClear}
|
|
520
|
+
* ```
|
|
521
|
+
*/
|
|
522
|
+
declare function usePendingTable(table: UrlTable, keys: string[]): UsePendingTableReturn;
|
|
523
|
+
|
|
524
|
+
declare const UNSAVED_CHANGES_EVENT = "unsaved-changes:confirm";
|
|
525
|
+
interface UseUnsavedChangesOptions {
|
|
526
|
+
/** Current form values to compare against initial */
|
|
527
|
+
formValues: Record<string, string>;
|
|
528
|
+
/** Initial form values snapshot (taken when data loads) */
|
|
529
|
+
initialValues: Record<string, string> | null;
|
|
530
|
+
/** Additional dirty flag from outside the form (e.g. pending avatar upload) */
|
|
531
|
+
extraDirty?: boolean;
|
|
532
|
+
/**
|
|
533
|
+
* Called when the user attempts to navigate away with unsaved changes.
|
|
534
|
+
* Must return a Promise that resolves to `true` (continue) or `false` (stay).
|
|
535
|
+
* Defaults to `window.confirm` with a generic message.
|
|
536
|
+
*/
|
|
537
|
+
confirmFn?: () => Promise<boolean>;
|
|
538
|
+
/**
|
|
539
|
+
* Message shown in the browser-native `beforeunload` dialog.
|
|
540
|
+
* Most modern browsers ignore custom messages and show their own text.
|
|
541
|
+
*/
|
|
542
|
+
beforeUnloadWarning?: string;
|
|
543
|
+
}
|
|
544
|
+
interface UseUnsavedChangesReturn {
|
|
545
|
+
/** Whether there are any unsaved changes (form or extra) */
|
|
546
|
+
isDirty: boolean;
|
|
547
|
+
/** Whether the form fields specifically have changed */
|
|
548
|
+
isFormDirty: boolean;
|
|
549
|
+
/** Call after a successful save to reset initial values to current */
|
|
550
|
+
markClean: () => void;
|
|
551
|
+
/** Prompt the user and return true if they confirmed leaving, false otherwise */
|
|
552
|
+
confirmLeave: () => Promise<boolean>;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* useUnsavedChanges
|
|
556
|
+
*
|
|
557
|
+
* Tracks unsaved form changes and warns users before navigating away.
|
|
558
|
+
*
|
|
559
|
+
* - Compares `formValues` to `initialValues` to detect form dirtiness
|
|
560
|
+
* - Accepts an optional `extraDirty` flag (e.g. pending file upload)
|
|
561
|
+
* - Registers a `beforeunload` handler while dirty
|
|
562
|
+
* - Exposes `confirmLeave()` which calls the provided `confirmFn` (or falls back
|
|
563
|
+
* to `window.confirm`) to handle navigation guards
|
|
564
|
+
* - `markClean()` resets the snapshot after a successful save
|
|
565
|
+
*/
|
|
566
|
+
declare function useUnsavedChanges({ formValues, initialValues, extraDirty, confirmFn, beforeUnloadWarning, }: UseUnsavedChangesOptions): UseUnsavedChangesReturn;
|
|
567
|
+
|
|
568
|
+
interface BulkActionItemFailure {
|
|
569
|
+
id: string;
|
|
570
|
+
reason: string;
|
|
571
|
+
}
|
|
572
|
+
interface BulkActionSummary {
|
|
573
|
+
total: number;
|
|
574
|
+
succeeded: number;
|
|
575
|
+
skipped: number;
|
|
576
|
+
failed: number;
|
|
577
|
+
}
|
|
578
|
+
interface BulkActionResult<TData = Record<string, unknown>> {
|
|
579
|
+
action: string;
|
|
580
|
+
summary: BulkActionSummary;
|
|
581
|
+
succeeded: string[];
|
|
582
|
+
skipped: string[];
|
|
583
|
+
failed: BulkActionItemFailure[];
|
|
584
|
+
data?: TData;
|
|
585
|
+
}
|
|
586
|
+
interface BulkActionPayload {
|
|
587
|
+
action: string;
|
|
588
|
+
ids: string[];
|
|
589
|
+
}
|
|
590
|
+
interface UseBulkActionOptions<TPayload extends BulkActionPayload, TData = Record<string, unknown>> {
|
|
591
|
+
/**
|
|
592
|
+
* Async function that POSTs to the bulk endpoint.
|
|
593
|
+
* Must return `Promise<BulkActionResult<TData>>`.
|
|
594
|
+
*/
|
|
595
|
+
mutationFn: (payload: TPayload) => Promise<BulkActionResult<TData>>;
|
|
596
|
+
/**
|
|
597
|
+
* Called when `mutationFn` resolves (even for partial failures).
|
|
598
|
+
* Inspect `result.summary` to build feedback.
|
|
599
|
+
*/
|
|
600
|
+
onSuccess?: (result: BulkActionResult<TData>, payload: TPayload) => void | Promise<void>;
|
|
601
|
+
/**
|
|
602
|
+
* Called when `mutationFn` rejects.
|
|
603
|
+
*/
|
|
604
|
+
onError?: (error: Error, payload: TPayload) => void;
|
|
605
|
+
/**
|
|
606
|
+
* When `true`, `execute()` parks the payload in `pendingPayload` instead of
|
|
607
|
+
* running immediately. The caller renders a confirm modal wired to
|
|
608
|
+
* `confirmAndExecute` / `cancelConfirm`.
|
|
609
|
+
*/
|
|
610
|
+
requiresConfirm?: boolean;
|
|
611
|
+
}
|
|
612
|
+
interface UseBulkActionReturn<TPayload extends BulkActionPayload, TData = Record<string, unknown>> {
|
|
613
|
+
execute: (payload: TPayload) => Promise<void>;
|
|
614
|
+
isLoading: boolean;
|
|
615
|
+
result: BulkActionResult<TData> | null;
|
|
616
|
+
error: Error | null;
|
|
617
|
+
reset: () => void;
|
|
618
|
+
pendingPayload: TPayload | null;
|
|
619
|
+
confirmAndExecute: () => Promise<void>;
|
|
620
|
+
cancelConfirm: () => void;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* useBulkAction
|
|
624
|
+
*
|
|
625
|
+
* Generic mutation hook for any `/bulk` endpoint.
|
|
626
|
+
* Handles loading state, partial-success result tracking, and an optional
|
|
627
|
+
* confirmation flow for destructive operations.
|
|
628
|
+
*
|
|
629
|
+
* Pair with `useBulkSelection` and a `BulkActionBar` component for the
|
|
630
|
+
* full admin list pattern.
|
|
631
|
+
*/
|
|
632
|
+
declare function useBulkAction<TPayload extends BulkActionPayload = BulkActionPayload, TData = Record<string, unknown>>(options: UseBulkActionOptions<TPayload, TData>): UseBulkActionReturn<TPayload, TData>;
|
|
633
|
+
|
|
634
|
+
export { type BulkActionItemFailure, type BulkActionPayload, type BulkActionResult, type BulkActionSummary, type CountdownRemaining, type GestureType, type KeyModifiers, type PendingTable, type SwipeDirection, UNSAVED_CHANGES_EVENT, type UseBulkActionOptions, type UseBulkActionReturn, type UseBulkSelectionOptions, type UseBulkSelectionReturn, type UseCameraOptions, type UseCameraReturn, type UseClickOutsideOptions, type UseGestureOptions, type UseKeyPressOptions, type UsePendingFiltersOptions, type UsePendingFiltersReturn, type UsePendingTableReturn, type UsePullToRefreshOptions, type UsePullToRefreshReturn, type UseSwipeOptions, type UseUnsavedChangesOptions, type UseUnsavedChangesReturn, type UseUrlTableOptions, useBreakpoint, useBulkAction, useBulkSelection, useCamera, useClickOutside, useCountdown, useGesture, useKeyPress, useLongPress, useMediaQuery, usePendingFilters, usePendingTable, usePullToRefresh, useSwipe, useUnsavedChanges, useUrlTable };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { RefObject } from 'react';
|
|
1
|
+
import { RefObject, Dispatch, SetStateAction } from 'react';
|
|
2
|
+
import * as next_navigation from 'next/navigation';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* useMediaQuery Hook
|
|
@@ -363,4 +364,271 @@ interface UseCameraReturn {
|
|
|
363
364
|
*/
|
|
364
365
|
declare function useCamera(): UseCameraReturn;
|
|
365
366
|
|
|
366
|
-
|
|
367
|
+
interface UseBulkSelectionOptions<T> {
|
|
368
|
+
/** The current page / list of items being displayed. */
|
|
369
|
+
items: T[];
|
|
370
|
+
/** Extract a stable unique key from each item (e.g. `item => item.id`). */
|
|
371
|
+
keyExtractor: (item: T) => string;
|
|
372
|
+
/**
|
|
373
|
+
* Maximum number of IDs that can be selected at once.
|
|
374
|
+
* @default 100
|
|
375
|
+
*/
|
|
376
|
+
maxSelection?: number;
|
|
377
|
+
}
|
|
378
|
+
interface UseBulkSelectionReturn {
|
|
379
|
+
selectedIds: string[];
|
|
380
|
+
selectedCount: number;
|
|
381
|
+
/** Returns `true` if the given ID is currently selected. */
|
|
382
|
+
isSelected: (id: string) => boolean;
|
|
383
|
+
/** `true` when every item on the current page is selected. */
|
|
384
|
+
isAllSelected: boolean;
|
|
385
|
+
/**
|
|
386
|
+
* `true` when some — but not all — items are selected.
|
|
387
|
+
* Use to set the indeterminate state on the header checkbox.
|
|
388
|
+
*/
|
|
389
|
+
isIndeterminate: boolean;
|
|
390
|
+
/** Toggle one item in or out of the selection. Respects `maxSelection`. */
|
|
391
|
+
toggle: (id: string) => void;
|
|
392
|
+
/**
|
|
393
|
+
* Select all items on the current page (up to `maxSelection`),
|
|
394
|
+
* or deselect all if every item is already selected.
|
|
395
|
+
*/
|
|
396
|
+
toggleAll: () => void;
|
|
397
|
+
/** Deselect everything. Call this after a bulk action completes. */
|
|
398
|
+
clearSelection: () => void;
|
|
399
|
+
/**
|
|
400
|
+
* Direct state setter — pass straight to a table's `onSelectionChange`
|
|
401
|
+
* or use when you need to replace the entire selection programmatically.
|
|
402
|
+
*/
|
|
403
|
+
setSelectedIds: Dispatch<SetStateAction<string[]>>;
|
|
404
|
+
}
|
|
405
|
+
declare function useBulkSelection<T>({ items, keyExtractor, maxSelection, }: UseBulkSelectionOptions<T>): UseBulkSelectionReturn;
|
|
406
|
+
|
|
407
|
+
interface UseUrlTableOptions {
|
|
408
|
+
/** Default param values used when a param is absent from the URL */
|
|
409
|
+
defaults?: Record<string, string>;
|
|
410
|
+
}
|
|
411
|
+
declare function useUrlTable(options?: UseUrlTableOptions): {
|
|
412
|
+
params: next_navigation.ReadonlyURLSearchParams;
|
|
413
|
+
get: (key: string) => string;
|
|
414
|
+
getNumber: (key: string, fallback?: number) => number;
|
|
415
|
+
set: (key: string, value: string) => void;
|
|
416
|
+
setMany: (updates: Record<string, string>) => void;
|
|
417
|
+
clear: (keys?: string[]) => void;
|
|
418
|
+
setPage: (page: number) => void;
|
|
419
|
+
setPageSize: (size: number) => void;
|
|
420
|
+
setSort: (sort: string) => void;
|
|
421
|
+
buildSieveParams: (sieveFilters: string) => string;
|
|
422
|
+
buildSearchParams: () => string;
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
type UrlTable$1 = ReturnType<typeof useUrlTable>;
|
|
426
|
+
interface UsePendingFiltersOptions {
|
|
427
|
+
/** The page's useUrlTable instance */
|
|
428
|
+
table: UrlTable$1;
|
|
429
|
+
/** URL param keys to manage (e.g. ['status', 'category', 'role']) */
|
|
430
|
+
keys: string[];
|
|
431
|
+
}
|
|
432
|
+
interface UsePendingFiltersReturn {
|
|
433
|
+
/** Current uncommitted selections per key (string[] per key) */
|
|
434
|
+
pending: Record<string, string[]>;
|
|
435
|
+
/** Values currently in the URL (committed) per key */
|
|
436
|
+
applied: Record<string, string[]>;
|
|
437
|
+
/** true when pending differs from applied */
|
|
438
|
+
isDirty: boolean;
|
|
439
|
+
/** Total number of selected values across all pending keys */
|
|
440
|
+
pendingCount: number;
|
|
441
|
+
/** Total number of selected values in the URL (for badge display) */
|
|
442
|
+
appliedCount: number;
|
|
443
|
+
/** Update one key in pending state (does NOT write to URL) */
|
|
444
|
+
set: (key: string, values: string[]) => void;
|
|
445
|
+
/** Write all pending keys to the URL (resets page to 1) */
|
|
446
|
+
apply: () => void;
|
|
447
|
+
/** Discard pending, revert to applied (URL) state */
|
|
448
|
+
reset: () => void;
|
|
449
|
+
/** Clear all keys in both pending state and the URL */
|
|
450
|
+
clear: () => void;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* usePendingFilters
|
|
454
|
+
*
|
|
455
|
+
* Manages local (uncommitted) filter state for a FilterDrawer or any deferred
|
|
456
|
+
* filter panel. Values are only written to the URL when `apply()` is called.
|
|
457
|
+
*
|
|
458
|
+
* Initialised from the current URL params on mount, so opening a drawer
|
|
459
|
+
* pre-fills any already-applied filters.
|
|
460
|
+
*
|
|
461
|
+
* @example
|
|
462
|
+
* ```ts
|
|
463
|
+
* const table = useUrlTable({ defaults: { pageSize: '25' } });
|
|
464
|
+
* const filters = usePendingFilters({ table, keys: ['status', 'category'] });
|
|
465
|
+
*
|
|
466
|
+
* <FilterDrawer
|
|
467
|
+
* onApply={() => { filters.apply(); setDrawerOpen(false); }}
|
|
468
|
+
* onReset={() => filters.clear()}
|
|
469
|
+
* activeCount={filters.appliedCount}
|
|
470
|
+
* >
|
|
471
|
+
* <FilterFacetSection
|
|
472
|
+
* title="Status"
|
|
473
|
+
* options={STATUS_OPTIONS}
|
|
474
|
+
* selected={filters.pending['status'] ?? []}
|
|
475
|
+
* onChange={(v) => filters.set('status', v)}
|
|
476
|
+
* />
|
|
477
|
+
* </FilterDrawer>
|
|
478
|
+
* ```
|
|
479
|
+
*/
|
|
480
|
+
declare function usePendingFilters({ table, keys, }: UsePendingFiltersOptions): UsePendingFiltersReturn;
|
|
481
|
+
|
|
482
|
+
type UrlTable = ReturnType<typeof useUrlTable>;
|
|
483
|
+
/**
|
|
484
|
+
* Minimal UrlTable-compatible interface consumed by *Filters components.
|
|
485
|
+
*/
|
|
486
|
+
interface PendingTable {
|
|
487
|
+
get: (key: string) => string;
|
|
488
|
+
set: (key: string, value: string) => void;
|
|
489
|
+
setMany: (updates: Record<string, string>) => void;
|
|
490
|
+
}
|
|
491
|
+
interface UsePendingTableReturn {
|
|
492
|
+
/** Drop-in UrlTable replacement that reads/writes to pending state */
|
|
493
|
+
pendingTable: PendingTable;
|
|
494
|
+
/** Count of applied (URL) filter values — use for the filter badge */
|
|
495
|
+
filterActiveCount: number;
|
|
496
|
+
/** Commit all pending changes to the URL (resets page to 1) */
|
|
497
|
+
onFilterApply: () => void;
|
|
498
|
+
/** Clear all filter keys from pending state and URL */
|
|
499
|
+
onFilterClear: () => void;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* usePendingTable
|
|
503
|
+
*
|
|
504
|
+
* A thin wrapper around `usePendingFilters` that exposes a `pendingTable`
|
|
505
|
+
* object matching the `UrlTable` interface (`get`, `set`, `setMany`).
|
|
506
|
+
*
|
|
507
|
+
* Drop this into any listing view to replace the per-filter `useState` +
|
|
508
|
+
* `handleFilterApply` + `handleFilterClear` boilerplate.
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* ```tsx
|
|
512
|
+
* const { pendingTable, filterActiveCount, onFilterApply, onFilterClear } =
|
|
513
|
+
* usePendingTable(table, ['status', 'category', 'minPrice', 'maxPrice']);
|
|
514
|
+
*
|
|
515
|
+
* // Pass pendingTable directly to any *Filters component:
|
|
516
|
+
* filterContent={<ProductFilters table={pendingTable} showStatus />}
|
|
517
|
+
* filterActiveCount={filterActiveCount}
|
|
518
|
+
* onFilterApply={onFilterApply}
|
|
519
|
+
* onFilterClear={onFilterClear}
|
|
520
|
+
* ```
|
|
521
|
+
*/
|
|
522
|
+
declare function usePendingTable(table: UrlTable, keys: string[]): UsePendingTableReturn;
|
|
523
|
+
|
|
524
|
+
declare const UNSAVED_CHANGES_EVENT = "unsaved-changes:confirm";
|
|
525
|
+
interface UseUnsavedChangesOptions {
|
|
526
|
+
/** Current form values to compare against initial */
|
|
527
|
+
formValues: Record<string, string>;
|
|
528
|
+
/** Initial form values snapshot (taken when data loads) */
|
|
529
|
+
initialValues: Record<string, string> | null;
|
|
530
|
+
/** Additional dirty flag from outside the form (e.g. pending avatar upload) */
|
|
531
|
+
extraDirty?: boolean;
|
|
532
|
+
/**
|
|
533
|
+
* Called when the user attempts to navigate away with unsaved changes.
|
|
534
|
+
* Must return a Promise that resolves to `true` (continue) or `false` (stay).
|
|
535
|
+
* Defaults to `window.confirm` with a generic message.
|
|
536
|
+
*/
|
|
537
|
+
confirmFn?: () => Promise<boolean>;
|
|
538
|
+
/**
|
|
539
|
+
* Message shown in the browser-native `beforeunload` dialog.
|
|
540
|
+
* Most modern browsers ignore custom messages and show their own text.
|
|
541
|
+
*/
|
|
542
|
+
beforeUnloadWarning?: string;
|
|
543
|
+
}
|
|
544
|
+
interface UseUnsavedChangesReturn {
|
|
545
|
+
/** Whether there are any unsaved changes (form or extra) */
|
|
546
|
+
isDirty: boolean;
|
|
547
|
+
/** Whether the form fields specifically have changed */
|
|
548
|
+
isFormDirty: boolean;
|
|
549
|
+
/** Call after a successful save to reset initial values to current */
|
|
550
|
+
markClean: () => void;
|
|
551
|
+
/** Prompt the user and return true if they confirmed leaving, false otherwise */
|
|
552
|
+
confirmLeave: () => Promise<boolean>;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* useUnsavedChanges
|
|
556
|
+
*
|
|
557
|
+
* Tracks unsaved form changes and warns users before navigating away.
|
|
558
|
+
*
|
|
559
|
+
* - Compares `formValues` to `initialValues` to detect form dirtiness
|
|
560
|
+
* - Accepts an optional `extraDirty` flag (e.g. pending file upload)
|
|
561
|
+
* - Registers a `beforeunload` handler while dirty
|
|
562
|
+
* - Exposes `confirmLeave()` which calls the provided `confirmFn` (or falls back
|
|
563
|
+
* to `window.confirm`) to handle navigation guards
|
|
564
|
+
* - `markClean()` resets the snapshot after a successful save
|
|
565
|
+
*/
|
|
566
|
+
declare function useUnsavedChanges({ formValues, initialValues, extraDirty, confirmFn, beforeUnloadWarning, }: UseUnsavedChangesOptions): UseUnsavedChangesReturn;
|
|
567
|
+
|
|
568
|
+
interface BulkActionItemFailure {
|
|
569
|
+
id: string;
|
|
570
|
+
reason: string;
|
|
571
|
+
}
|
|
572
|
+
interface BulkActionSummary {
|
|
573
|
+
total: number;
|
|
574
|
+
succeeded: number;
|
|
575
|
+
skipped: number;
|
|
576
|
+
failed: number;
|
|
577
|
+
}
|
|
578
|
+
interface BulkActionResult<TData = Record<string, unknown>> {
|
|
579
|
+
action: string;
|
|
580
|
+
summary: BulkActionSummary;
|
|
581
|
+
succeeded: string[];
|
|
582
|
+
skipped: string[];
|
|
583
|
+
failed: BulkActionItemFailure[];
|
|
584
|
+
data?: TData;
|
|
585
|
+
}
|
|
586
|
+
interface BulkActionPayload {
|
|
587
|
+
action: string;
|
|
588
|
+
ids: string[];
|
|
589
|
+
}
|
|
590
|
+
interface UseBulkActionOptions<TPayload extends BulkActionPayload, TData = Record<string, unknown>> {
|
|
591
|
+
/**
|
|
592
|
+
* Async function that POSTs to the bulk endpoint.
|
|
593
|
+
* Must return `Promise<BulkActionResult<TData>>`.
|
|
594
|
+
*/
|
|
595
|
+
mutationFn: (payload: TPayload) => Promise<BulkActionResult<TData>>;
|
|
596
|
+
/**
|
|
597
|
+
* Called when `mutationFn` resolves (even for partial failures).
|
|
598
|
+
* Inspect `result.summary` to build feedback.
|
|
599
|
+
*/
|
|
600
|
+
onSuccess?: (result: BulkActionResult<TData>, payload: TPayload) => void | Promise<void>;
|
|
601
|
+
/**
|
|
602
|
+
* Called when `mutationFn` rejects.
|
|
603
|
+
*/
|
|
604
|
+
onError?: (error: Error, payload: TPayload) => void;
|
|
605
|
+
/**
|
|
606
|
+
* When `true`, `execute()` parks the payload in `pendingPayload` instead of
|
|
607
|
+
* running immediately. The caller renders a confirm modal wired to
|
|
608
|
+
* `confirmAndExecute` / `cancelConfirm`.
|
|
609
|
+
*/
|
|
610
|
+
requiresConfirm?: boolean;
|
|
611
|
+
}
|
|
612
|
+
interface UseBulkActionReturn<TPayload extends BulkActionPayload, TData = Record<string, unknown>> {
|
|
613
|
+
execute: (payload: TPayload) => Promise<void>;
|
|
614
|
+
isLoading: boolean;
|
|
615
|
+
result: BulkActionResult<TData> | null;
|
|
616
|
+
error: Error | null;
|
|
617
|
+
reset: () => void;
|
|
618
|
+
pendingPayload: TPayload | null;
|
|
619
|
+
confirmAndExecute: () => Promise<void>;
|
|
620
|
+
cancelConfirm: () => void;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* useBulkAction
|
|
624
|
+
*
|
|
625
|
+
* Generic mutation hook for any `/bulk` endpoint.
|
|
626
|
+
* Handles loading state, partial-success result tracking, and an optional
|
|
627
|
+
* confirmation flow for destructive operations.
|
|
628
|
+
*
|
|
629
|
+
* Pair with `useBulkSelection` and a `BulkActionBar` component for the
|
|
630
|
+
* full admin list pattern.
|
|
631
|
+
*/
|
|
632
|
+
declare function useBulkAction<TPayload extends BulkActionPayload = BulkActionPayload, TData = Record<string, unknown>>(options: UseBulkActionOptions<TPayload, TData>): UseBulkActionReturn<TPayload, TData>;
|
|
633
|
+
|
|
634
|
+
export { type BulkActionItemFailure, type BulkActionPayload, type BulkActionResult, type BulkActionSummary, type CountdownRemaining, type GestureType, type KeyModifiers, type PendingTable, type SwipeDirection, UNSAVED_CHANGES_EVENT, type UseBulkActionOptions, type UseBulkActionReturn, type UseBulkSelectionOptions, type UseBulkSelectionReturn, type UseCameraOptions, type UseCameraReturn, type UseClickOutsideOptions, type UseGestureOptions, type UseKeyPressOptions, type UsePendingFiltersOptions, type UsePendingFiltersReturn, type UsePendingTableReturn, type UsePullToRefreshOptions, type UsePullToRefreshReturn, type UseSwipeOptions, type UseUnsavedChangesOptions, type UseUnsavedChangesReturn, type UseUrlTableOptions, useBreakpoint, useBulkAction, useBulkSelection, useCamera, useClickOutside, useCountdown, useGesture, useKeyPress, useLongPress, useMediaQuery, usePendingFilters, usePendingTable, usePullToRefresh, useSwipe, useUnsavedChanges, useUrlTable };
|