@himanshu-sorathiya/react-kit 1.0.25 → 1.0.27

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.d.ts CHANGED
@@ -3,33 +3,264 @@
3
3
  import React$1 from 'react';
4
4
  import { CSSProperties, Key, RefObject } from 'react';
5
5
 
6
+ /**
7
+ * The native event that triggered a `useClickOutside` handler. Determined
8
+ * by whichever `eventType` was configured — `MouseEvent` for
9
+ * `click`/`mousedown`/`mouseup`, `TouchEvent` for `touchstart`/`touchend`,
10
+ * `PointerEvent` for `pointerdown`/`pointerup`.
11
+ */
6
12
  export type ClickOutsideEvent = MouseEvent | TouchEvent | PointerEvent | Event;
7
- export type ClickOutsideTarget = HTMLElement | null;
13
+ /**
14
+ * A single element to check clicks against, or `null` if it isn't mounted
15
+ * yet.
16
+ */
17
+ export type ClickOutsideTarget = Element | null;
18
+ /**
19
+ * A way of referring to a single {@link ClickOutsideTarget}: a React ref
20
+ * that will (eventually) point at the element, the element itself, or
21
+ * `null`.
22
+ *
23
+ * A ref whose `current` is `null` — for example, because the element hasn't
24
+ * mounted yet — is treated as "outside" for that entry rather than blocking
25
+ * detection. See `useClickOutside`'s docs for details.
26
+ */
8
27
  export type ClickOutsideTargetRef = React$1.RefObject<ClickOutsideTarget> | ClickOutsideTarget;
28
+ /**
29
+ * Native events `useClickOutside` can listen for. Defaults to `mousedown`
30
+ * and `touchstart`, which fire before `click`/`mouseup` — this avoids
31
+ * misfiring when a user starts a drag or text selection inside the target
32
+ * and releases outside it.
33
+ */
34
+ export type ClickOutsideEventName = "mousedown" | "mouseup" | "click" | "touchstart" | "touchend" | "pointerdown" | "pointerup";
35
+ /**
36
+ * Options accepted by `useClickOutside`.
37
+ */
9
38
  export interface UseClickOutsideOptions {
39
+ /**
40
+ * Whether the listener is active. Setting this to `false` fully detaches
41
+ * the underlying listener rather than just skipping the check on each
42
+ * click, so there's no runtime cost while disabled.
43
+ *
44
+ * @default true
45
+ */
10
46
  enabled?: boolean;
11
- eventType?: string | string[];
47
+ /**
48
+ * The event(s) that count as a "click." See {@link ClickOutsideEventName}
49
+ * for why `mousedown`/`touchstart` are the default.
50
+ *
51
+ * @default ["mousedown", "touchstart"]
52
+ */
53
+ eventType?: ClickOutsideEventName | ClickOutsideEventName[];
54
+ /**
55
+ * Whether the listener is registered in the capture phase.
56
+ *
57
+ * Defaults to `true` so this keeps working even if some element between
58
+ * the click and `document` calls `event.stopPropagation()` — a common
59
+ * cause of "click outside stopped working" bugs in bubble-phase
60
+ * listeners.
61
+ *
62
+ * @default true
63
+ */
64
+ capture?: boolean;
12
65
  }
13
- export type UseClickOutsideReturn = void;
66
+ /**
67
+ * A function that detaches the listener registered by `useClickOutside`
68
+ * immediately, without waiting for the component to unmount.
69
+ *
70
+ * Safe to call more than once. Note that this does not permanently disable
71
+ * the hook: if `target`, `eventType`, `enabled`, or `capture` change
72
+ * afterwards, a new listener may be attached again on the next render.
73
+ */
74
+ export type UseClickOutsideReturn = () => void;
75
+ /**
76
+ * Calls `handler` when a click (or the configured event type) happens
77
+ * outside of `target`.
78
+ *
79
+ * `target` may be a single element/ref, or an array of them — the handler
80
+ * only fires when the click is outside *every* target in the array. An
81
+ * unmounted target (a ref whose `current` is `null`) is treated as
82
+ * "outside" for its own entry rather than blocking detection for the
83
+ * others, so it's safe to pass refs that haven't attached yet.
84
+ *
85
+ * @param target The element(s) to detect clicks outside of. Accepts a ref, a direct
86
+ * element, `null`, or an array mixing any of those.
87
+ * @param handler Called with the native event when a click outside is detected. Doesn't
88
+ * need to be memoized.
89
+ * @param options See {@link UseClickOutsideOptions}.
90
+ * @returns A function that detaches the listener on demand.
91
+ *
92
+ * @example
93
+ * ```tsx
94
+ * const modalRef = useRef<HTMLDivElement>(null);
95
+ * useClickOutside(modalRef, () => setOpen(false));
96
+ * ```
97
+ *
98
+ * @example
99
+ * Checking outside multiple elements at once — for example, a dropdown that
100
+ * shouldn't close when its own trigger button is clicked:
101
+ * ```tsx
102
+ * const triggerRef = useRef<HTMLButtonElement>(null);
103
+ * const panelRef = useRef<HTMLDivElement>(null);
104
+ * useClickOutside([triggerRef, panelRef], () => setOpen(false));
105
+ * ```
106
+ */
14
107
  export declare function useClickOutside(target: ClickOutsideTargetRef | ClickOutsideTargetRef[], handler: (event: ClickOutsideEvent) => void, options?: UseClickOutsideOptions): UseClickOutsideReturn;
108
+ /**
109
+ * Any valid DOM event target — the broadest type a listener can be attached
110
+ * to. Used as the generic constraint for {@link UseEventListenerOptions} and
111
+ * {@link TargetRef}.
112
+ */
15
113
  export type TargetType = EventTarget;
114
+ /**
115
+ * A way of referring to a listener target: a React ref that will
116
+ * (eventually) point at the target, the target itself, or `null`.
117
+ *
118
+ * Passing `null` — or a ref whose `current` is `null` — means no listener is
119
+ * attached.
120
+ */
16
121
  export type TargetRef<T extends TargetType> = React$1.RefObject<T | null> | T | null;
122
+ /**
123
+ * Options accepted by `useEventListener`, extending the native
124
+ * `AddEventListenerOptions` (`capture`, `passive`, `once`) with a `target`
125
+ * to attach to.
126
+ */
17
127
  export interface UseEventListenerOptions<T extends TargetType> extends AddEventListenerOptions {
128
+ /**
129
+ * The element, ref, `window`, or `document` to attach the listener to.
130
+ *
131
+ * - Omitted → defaults to `window` (or does nothing during SSR, where
132
+ * `window` doesn't exist).
133
+ * - `null`, or a ref whose `current` is `null` → no listener is attached.
134
+ */
18
135
  target?: TargetRef<T>;
136
+ /**
137
+ * An `AbortSignal` to detach the listener(s) from outside the hook.
138
+ *
139
+ * This is combined with the hook's own internal cleanup — aborting this
140
+ * signal detaches the listener(s) immediately, the same as calling the
141
+ * function the hook returns.
142
+ */
143
+ signal?: AbortSignal;
19
144
  }
20
- export type UseEventListenerReturn = void;
145
+ /**
146
+ * A function that detaches the listener(s) registered by `useEventListener`
147
+ * immediately, without waiting for the component to unmount.
148
+ *
149
+ * Safe to call more than once — it's a no-op after the first call. Note
150
+ * that this does not permanently disable the hook: if its dependencies
151
+ * (event name(s), target, `capture`, `passive`, `once`, or `signal`) change
152
+ * afterwards, a new listener may be attached again on the next render.
153
+ */
154
+ export type UseEventListenerReturn = () => void;
155
+ /**
156
+ * Listens for one or more events on `window` — the default target when none
157
+ * is specified.
158
+ *
159
+ * @param eventName A single event name, or an array of event names, to listen for.
160
+ * @param handler Called with the native event whenever it fires. Doesn't need to be
161
+ * memoized — the latest `handler` is always used, and changing it does not
162
+ * re-attach the listener.
163
+ * @param options Optional. `target` may be omitted (defaults to `window`), or set
164
+ * explicitly to `window` or `null` (to disable).
165
+ * @returns A function that detaches the listener(s) on demand.
166
+ *
167
+ * @example
168
+ * ```tsx
169
+ * useEventListener("resize", () => {
170
+ * console.log(window.innerWidth);
171
+ * });
172
+ * ```
173
+ */
21
174
  export declare function useEventListener<K extends keyof WindowEventMap>(eventName: K | K[], handler: (event: WindowEventMap[K]) => void, options?: UseEventListenerOptions<Window> & {
22
175
  target?: Window | null | undefined;
23
176
  }): UseEventListenerReturn;
177
+ /**
178
+ * Listens for one or more events on `document`. `target` is required to
179
+ * distinguish this overload from the `window` one.
180
+ *
181
+ * @param eventName A single event name, or an array of event names, to listen for.
182
+ * @param handler Called with the native event whenever it fires. Doesn't need to be
183
+ * memoized — the latest `handler` is always used, and changing it does not
184
+ * re-attach the listener.
185
+ * @param options `target` must be `document`, a ref pointing at `document`, or `null`
186
+ * (to disable).
187
+ * @returns A function that detaches the listener(s) on demand.
188
+ *
189
+ * @example
190
+ * ```tsx
191
+ * useEventListener("visibilitychange", () => {
192
+ * console.log(document.visibilityState);
193
+ * }, { target: document });
194
+ * ```
195
+ */
24
196
  export declare function useEventListener<K extends keyof DocumentEventMap>(eventName: K | K[], handler: (event: DocumentEventMap[K]) => void, options: UseEventListenerOptions<Document> & {
25
197
  target: Document | React$1.RefObject<Document | null> | null;
26
198
  }): UseEventListenerReturn;
199
+ /**
200
+ * Listens for one or more events on an `HTMLElement`, via a ref or the
201
+ * element itself.
202
+ *
203
+ * @param eventName A single event name, or an array of event names, to listen for.
204
+ * @param handler Called with the native event whenever it fires. Doesn't need to be
205
+ * memoized — the latest `handler` is always used, and changing it does not
206
+ * re-attach the listener.
207
+ * @param options `target` must be the element, a ref to it, or `null` (to disable —
208
+ * for example while the ref hasn't attached to a DOM node yet).
209
+ * @returns A function that detaches the listener(s) on demand.
210
+ *
211
+ * @example
212
+ * ```tsx
213
+ * const buttonRef = useRef<HTMLButtonElement>(null);
214
+ * useEventListener("click", () => {
215
+ * console.log("clicked");
216
+ * }, { target: buttonRef });
217
+ * ```
218
+ */
27
219
  export declare function useEventListener<K extends keyof HTMLElementEventMap, T extends HTMLElement = HTMLElement>(eventName: K | K[], handler: (event: HTMLElementEventMap[K]) => void, options: UseEventListenerOptions<T> & {
28
220
  target: T | React$1.RefObject<T | null> | null;
29
221
  }): UseEventListenerReturn;
222
+ /**
223
+ * Listens for one or more events on an `SVGElement`, via a ref or the
224
+ * element itself.
225
+ *
226
+ * @param eventName A single event name, or an array of event names, to listen for.
227
+ * @param handler Called with the native event whenever it fires. Doesn't need to be
228
+ * memoized — the latest `handler` is always used, and changing it does not
229
+ * re-attach the listener.
230
+ * @param options `target` must be the element, a ref to it, or `null` (to disable).
231
+ * @returns A function that detaches the listener(s) on demand.
232
+ *
233
+ * @example
234
+ * ```tsx
235
+ * const circleRef = useRef<SVGCircleElement>(null);
236
+ * useEventListener("click", () => {
237
+ * console.log("circle clicked");
238
+ * }, { target: circleRef });
239
+ * ```
240
+ */
30
241
  export declare function useEventListener<K extends keyof SVGElementEventMap, T extends SVGElement = SVGElement>(eventName: K | K[], handler: (event: SVGElementEventMap[K]) => void, options: UseEventListenerOptions<T> & {
31
242
  target: T | React$1.RefObject<T | null> | null;
32
243
  }): UseEventListenerReturn;
244
+ /**
245
+ * Listens for one or more events on any other `EventTarget` — a custom
246
+ * event emitter, `ShadowRoot`, `MessagePort`, and so on. Since there's no
247
+ * matching `*EventMap` for arbitrary targets, events are typed as the
248
+ * generic `Event`.
249
+ *
250
+ * @param eventName A single event name, or an array of event names, to listen for.
251
+ * @param handler Called with the native event whenever it fires. Doesn't need to be
252
+ * memoized — the latest `handler` is always used, and changing it does not
253
+ * re-attach the listener.
254
+ * @param options `target` must be the target, a ref to it, or `null` (to disable).
255
+ * @returns A function that detaches the listener(s) on demand.
256
+ *
257
+ * @example
258
+ * ```tsx
259
+ * useEventListener("message", (event) => {
260
+ * console.log(event);
261
+ * }, { target: myMessagePort });
262
+ * ```
263
+ */
33
264
  export declare function useEventListener<K extends string, T extends TargetType = TargetType>(eventName: K | K[], handler: (event: Event) => void, options: UseEventListenerOptions<T> & {
34
265
  target: T | React$1.RefObject<T | null> | null;
35
266
  }): UseEventListenerReturn;
@@ -38,27 +269,154 @@ declare const validKeyEventTypes: readonly [
38
269
  "keyup",
39
270
  "keypress"
40
271
  ];
272
+ /**
273
+ * The keyboard event types `useKey` can listen for. See
274
+ * {@link validKeyEventTypes}.
275
+ */
41
276
  export type KeyEventType = (typeof validKeyEventTypes)[number];
42
- export interface BaseKeyOptions {
277
+ /**
278
+ * Options shared by both variants of {@link UseKeyOptions}.
279
+ */
280
+ export interface UseKeyBaseOptions {
281
+ /**
282
+ * Whether the listener is active. Setting this to `false` fully detaches
283
+ * the underlying listener rather than just skipping the check on each
284
+ * keystroke, so there's no runtime cost while disabled.
285
+ *
286
+ * @default true
287
+ */
43
288
  enabled?: boolean;
44
- target?: React$1.RefObject<HTMLElement | null> | Window;
289
+ /**
290
+ * The element, ref, `window`, or `document` to attach the listener to.
291
+ *
292
+ * @default window
293
+ */
294
+ target?: React$1.RefObject<HTMLElement | null> | HTMLElement | Window | Document | null;
295
+ /**
296
+ * Whether to call `event.preventDefault()` when `key` matches. Applied
297
+ * before `handler` is called, so it still takes effect even if `handler`
298
+ * throws.
299
+ *
300
+ * @default true
301
+ */
45
302
  preventDefault?: boolean;
303
+ /**
304
+ * Whether to call `event.stopPropagation()` when `key` matches. Applied
305
+ * before `handler` is called, so it still takes effect even if `handler`
306
+ * throws.
307
+ *
308
+ * @default true
309
+ */
46
310
  stopPropagation?: boolean;
311
+ /**
312
+ * Whether the listener is registered in the capture phase.
313
+ *
314
+ * Unlike `useClickOutside`, this defaults to `false`. Flip it to `true`
315
+ * if a descendant element calling `event.stopPropagation()` is
316
+ * preventing this shortcut from firing.
317
+ *
318
+ * @default false
319
+ */
320
+ capture?: boolean;
321
+ /**
322
+ * Whether to ignore the keystroke while focus is inside an `<input>`,
323
+ * `<textarea>`, `<select>`, or any `contenteditable` element — so a
324
+ * shortcut like a bare `"s"` doesn't fire while someone is just typing.
325
+ *
326
+ * @default true
327
+ */
47
328
  ignoreWhenFocusedInInputs?: boolean;
329
+ /**
330
+ * Whether the Ctrl key must be held for a match.
331
+ * @default false
332
+ */
48
333
  ctrlKey?: boolean;
334
+ /**
335
+ * Whether the Shift key must be held for a match.
336
+ * @default false
337
+ */
49
338
  shiftKey?: boolean;
339
+ /**
340
+ * Whether the Alt key (Option, on Mac) must be held for a match.
341
+ * @default false
342
+ */
50
343
  altKey?: boolean;
344
+ /**
345
+ * Whether the Meta key (Cmd on Mac, the Windows key elsewhere) must be
346
+ * held for a match.
347
+ * @default false
348
+ */
51
349
  metaKey?: boolean;
52
350
  }
53
- export type KeyOptions = BaseKeyOptions & ({
54
- eventType?: "keydown" | "keypress";
351
+ /**
352
+ * Options accepted by `useKey`.
353
+ *
354
+ * `preventRepeat` is only valid together with `eventType: "keydown"` or
355
+ * `"keypress"` — TypeScript rejects it on `"keyup"`, since a keyup event is
356
+ * never marked as auto-repeating.
357
+ */
358
+ export type UseKeyOptions = UseKeyBaseOptions & ({
359
+ /**
360
+ * Which keyboard event to listen for.
361
+ * @default "keydown"
362
+ */
363
+ eventType?: Extract<KeyEventType, "keydown" | "keypress">;
364
+ /**
365
+ * If `true`, ignores auto-repeated events fired while the key is
366
+ * held down (based on the native `KeyboardEvent.repeat` flag), so
367
+ * `handler` only fires once per physical press rather than
368
+ * repeatedly while it's held.
369
+ *
370
+ * @default false
371
+ */
55
372
  preventRepeat?: boolean;
56
373
  } | {
57
- eventType: "keyup";
374
+ eventType: Extract<KeyEventType, "keyup">;
58
375
  preventRepeat?: never;
59
376
  });
60
- export type UseKeyReturn = void;
61
- export declare function useKey(key: string, handler: (e: KeyboardEvent) => void, { enabled, preventDefault, stopPropagation, eventType, preventRepeat, ignoreWhenFocusedInInputs, ctrlKey, shiftKey, altKey, metaKey, target, }?: KeyOptions): UseKeyReturn;
377
+ /**
378
+ * A function that detaches the listener registered by `useKey` immediately,
379
+ * without waiting for the component to unmount.
380
+ *
381
+ * Safe to call more than once. Note that this does not permanently disable
382
+ * the hook: if `eventType`, `enabled`, `target`, or `capture` change
383
+ * afterwards, a new listener may be attached again on the next render.
384
+ * Changing `key` — or any of the modifier-matching options — does *not*
385
+ * cause a re-attach; those are picked up fresh on the next keystroke
386
+ * without the underlying listener ever being torn down.
387
+ */
388
+ export type UseKeyReturn = () => void;
389
+ /**
390
+ * Calls `handler` when `key` is pressed (or released, depending on
391
+ * `eventType`), optionally matching an exact combination of modifier keys.
392
+ *
393
+ * Ignores keystrokes that occur during IME composition (for example, while
394
+ * typing pinyin or romaji before a CJK character is confirmed), so
395
+ * shortcuts don't misfire or interfere with the IME's own confirmation key
396
+ * — often Enter. By default, also ignores keystrokes while focus is inside
397
+ * a text input, textarea, select, or contenteditable element — see
398
+ * `ignoreWhenFocusedInInputs` in {@link UseKeyOptions}.
399
+ *
400
+ * @param key The key to match, compared case-insensitively against
401
+ * `KeyboardEvent.key` (e.g. `"Escape"`, `"a"`, `"Enter"`).
402
+ * @param handler Called with the native event when a match is found. Doesn't need to be
403
+ * memoized.
404
+ * @param options See {@link UseKeyOptions}.
405
+ * @returns A function that detaches the listener on demand.
406
+ *
407
+ * @example
408
+ * ```tsx
409
+ * useKey("Escape", () => setOpen(false));
410
+ * ```
411
+ *
412
+ * @example
413
+ * Matching a modifier combination — all four modifier flags are matched
414
+ * exactly, so this only fires for Ctrl+K alone, not Ctrl+Shift+K:
415
+ * ```tsx
416
+ * useKey("k", () => openCommandPalette(), { ctrlKey: true });
417
+ * ```
418
+ */
419
+ export declare function useKey(key: string, handler: (event: KeyboardEvent) => void, options?: UseKeyOptions): UseKeyReturn;
62
420
  export interface DebounceOptions {
63
421
  maxWait?: number;
64
422
  leading?: boolean;
@@ -458,43 +816,295 @@ export interface UseSortReturn<T> {
458
816
  getSortIndex: (id: string) => number | undefined;
459
817
  }
460
818
  export declare function useSort<T>(data?: T[], initialSorts?: SortState): UseSortReturn<T>;
819
+ /**
820
+ * Defines how a value of type `T` is converted to and from the string
821
+ * format that `localStorage`/`sessionStorage` can actually store — the Web
822
+ * Storage API only ever stores strings.
823
+ *
824
+ * Implement this to store types the default JSON-based serializer can't
825
+ * round-trip faithfully, e.g. `Map`, `Set`, `Date`, or `bigint` — see
826
+ * `mapSerializer`, `setSerializer`, `dateSerializer`, and
827
+ * `bigIntSerializer` in `serializers.ts` for ready-made ones.
828
+ *
829
+ * @typeParam T - The in-memory value type this serializer handles.
830
+ */
461
831
  export interface StorageSerializer<T> {
832
+ /** Converts an in-memory value into the string that gets stored. */
462
833
  serialize: (value: T) => string;
834
+ /**
835
+ * Converts a stored string back into an in-memory value.
836
+ *
837
+ * @throws If the raw string can't be converted back into `T`. The hook
838
+ * catches this, falls back to `initialValue`, and reports the error —
839
+ * see `onError` on {@link BaseStorageOptions}.
840
+ */
463
841
  deserialize: (raw: string) => T;
464
842
  }
843
+ /**
844
+ * Options shared by `useLocalStorage` and `useSessionStorage`.
845
+ *
846
+ * @typeParam T - The type of value being stored.
847
+ */
465
848
  export interface BaseStorageOptions<T> {
849
+ /**
850
+ * Custom (de)serializer for values that don't round-trip through
851
+ * `JSON.stringify`/`JSON.parse` cleanly.
852
+ *
853
+ * @defaultValue `defaultSerializer` (plain `JSON.stringify`/`JSON.parse`)
854
+ */
466
855
  serializer?: StorageSerializer<T>;
856
+ /**
857
+ * Whether to synchronously read the existing stored value on mount.
858
+ *
859
+ * - `true` (default): `value` reflects storage from the very first
860
+ * render it's allowed to (see the SSR note below).
861
+ * - `false`: `value` starts as `undefined` and only reflects storage
862
+ * once `isHydrated` becomes `true`, one render after mount. Use this
863
+ * if you'd rather render a loading/skeleton state than briefly show a
864
+ * value that might change right after.
865
+ *
866
+ * Either way, on the server — and during the client's hydration render
867
+ * — `value` is always `initialValue`. This option only affects timing
868
+ * on the client, after that point.
869
+ *
870
+ * @defaultValue `true`
871
+ */
467
872
  initializeWithValue?: boolean;
873
+ /**
874
+ * Whether other instances of this hook watching the *same key* in the
875
+ * *same tab* stay in sync with each other. Implemented via a
876
+ * `CustomEvent` dispatched on `window` — the browser's native `storage`
877
+ * event never fires in the tab that made the change, so without this,
878
+ * two components reading the same key in one tab would drift apart.
879
+ *
880
+ * @defaultValue `true`
881
+ */
468
882
  sameInstanceSync?: boolean;
883
+ /**
884
+ * Called whenever the hook hits an unexpected condition: a failed
885
+ * read, a failed write, a failed cross-instance deserialize, or an
886
+ * attempt to change the storage key at runtime. Fires in every
887
+ * environment, including production — use this for telemetry/error
888
+ * reporting.
889
+ *
890
+ * This is *not* a replacement for the dev-only `console.warn` the hook
891
+ * also emits for the same conditions (visible when
892
+ * `process.env.NODE_ENV !== "production"`) — both fire independently.
893
+ */
894
+ onError?: (error: Error) => void;
469
895
  }
896
+ /**
897
+ * Payload carried by the same-tab `CustomEvent` used for
898
+ * {@link BaseStorageOptions.sameInstanceSync}. Internal — not part of the
899
+ * public hook API, but exported so `useStorageEngine.ts` can import it.
900
+ */
470
901
  export interface StorageCustomEventDetail {
902
+ /** The new serialized value, or `null` if the key was removed. */
471
903
  value: string | null;
904
+ /**
905
+ * A per-hook-instance identifier, used so an instance can recognize —
906
+ * and ignore — the event it just dispatched itself.
907
+ */
472
908
  instanceId: symbol;
473
909
  }
474
- export interface UseLocalStorageOptions<T> extends BaseStorageOptions<T> {
475
- crossInstanceSync?: boolean;
476
- }
477
- export interface UseLocalStorageReturn<T> {
910
+ /**
911
+ * The shape returned by {@link useStorageEngine} — and, re-exported, by
912
+ * both `useLocalStorage` and `useSessionStorage`.
913
+ *
914
+ * @typeParam T - The type of value being stored.
915
+ */
916
+ interface UseStorageEngineReturn<T> {
917
+ /**
918
+ * The current value.
919
+ *
920
+ * - `undefined` if nothing is stored yet and no `initialValue` was
921
+ * given, or — when `initializeWithValue: false` — before hydration
922
+ * completes.
923
+ * - On the server, and during the client's hydration render, this is
924
+ * always `initialValue`: real storage can only be read client-side,
925
+ * and reading it any earlier would produce a hydration mismatch.
926
+ */
478
927
  value: T | undefined;
928
+ /**
929
+ * Writes a new value to storage. Accepts either the value directly, or
930
+ * an updater function that receives the current value and returns the
931
+ * next one — the same convention as `useState`'s setter.
932
+ *
933
+ * A no-op if storage isn't available (SSR, or storage access blocked).
934
+ */
479
935
  setValue: (valueOrUpdater: T | ((prev: T | undefined) => T)) => void;
936
+ /**
937
+ * Removes the key from storage entirely and resets `value` back to
938
+ * whatever `initialValue` was passed to the hook.
939
+ *
940
+ * A no-op if storage isn't available (SSR, or storage access blocked).
941
+ */
480
942
  removeValue: () => void;
943
+ /**
944
+ * `true` once the client has mounted and the hook has settled on its
945
+ * real (non-server-snapshot) value. Useful for showing a loading state
946
+ * instead of a value that might change the instant hydration finishes.
947
+ */
481
948
  isHydrated: boolean;
949
+ /**
950
+ * The most recent error the hook encountered — a failed read, write,
951
+ * or cross-instance sync, or an attempted key change — or `null` if
952
+ * nothing has gone wrong (or an error was cleared by a subsequent
953
+ * successful write/remove). See `onError` on {@link BaseStorageOptions}
954
+ * for an imperative alternative to reading this reactively.
955
+ */
482
956
  error: Error | null;
483
957
  }
484
- export declare function useLocalStorage<T = unknown>(key: string, initialValue?: T, options?: UseLocalStorageOptions<T>): UseLocalStorageReturn<T>;
485
- export type UseSessionStorageOptions<T> = BaseStorageOptions<T>;
486
- export interface UseSessionStorageReturn<T> {
487
- value: T | undefined;
488
- setValue: (valueOrUpdater: T | ((prev: T | undefined) => T)) => void;
489
- removeValue: () => void;
490
- isHydrated: boolean;
491
- error: Error | null;
958
+ /**
959
+ * Options accepted by `useLocalStorage`.
960
+ *
961
+ * @typeParam T - The type of value being stored.
962
+ */
963
+ export interface UseLocalStorageOptions<T> extends BaseStorageOptions<T> {
964
+ /**
965
+ * Whether this hook instance should sync with the same key changing in
966
+ * *other tabs/windows* on the same origin, via the browser's native
967
+ * `storage` event. Has no `sessionStorage` equivalent — sessionStorage
968
+ * isn't shared across tabs, so there's nothing to sync in that case.
969
+ *
970
+ * @defaultValue `true`
971
+ */
972
+ crossInstanceSync?: boolean;
492
973
  }
493
- export declare function useSessionStorage<T = unknown>(key: string, initialValue?: T, options?: UseSessionStorageOptions<T>): UseSessionStorageReturn<T>;
974
+ /**
975
+ * Reads and writes a `localStorage` key, kept in sync with React state.
976
+ *
977
+ * - Persists across page reloads and browser restarts (unlike
978
+ * `useSessionStorage`).
979
+ * - Stays in sync with every component in the current tab watching the
980
+ * same key — see {@link UseLocalStorageOptions.sameInstanceSync} — and
981
+ * with other tabs/windows on the same origin — see
982
+ * {@link UseLocalStorageOptions.crossInstanceSync}.
983
+ * - Safe under SSR: on the server, and during the client's hydration
984
+ * render, `value` is always `initialValue`. The real stored value is
985
+ * only read client-side, immediately after hydration.
986
+ *
987
+ * @typeParam T - The type of value being stored. Defaults to `unknown` if
988
+ * omitted — pass an explicit type argument for anything beyond ad-hoc use.
989
+ * @param key - The `localStorage` key to read and write. Changing this on
990
+ * a later render isn't supported; the hook warns (dev console + `onError`)
991
+ * and keeps using the original key if you do.
992
+ * @param initialValue - Used when nothing is stored yet, as the value
993
+ * shown before hydration completes, and as what `removeValue` resets to.
994
+ * @param options - See {@link UseLocalStorageOptions}.
995
+ * @returns `{ value, setValue, removeValue, isHydrated, error }`.
996
+ *
997
+ * @example
998
+ * Basic usage:
999
+ * ```tsx
1000
+ * const { value: theme, setValue: setTheme } = useLocalStorage<"light" | "dark">("theme", "light");
1001
+ *
1002
+ * <button onClick={() => setTheme(prev => (prev === "light" ? "dark" : "light"))}>
1003
+ * Toggle theme
1004
+ * </button>
1005
+ * ```
1006
+ *
1007
+ * @example
1008
+ * With a custom serializer and error reporting:
1009
+ * ```tsx
1010
+ * const { value, setValue, error } = useLocalStorage("lastSeen", new Date(), {
1011
+ * serializer: dateSerializer,
1012
+ * onError: (err) => reportToErrorTracker(err),
1013
+ * });
1014
+ * ```
1015
+ */
1016
+ export declare function useLocalStorage<T = unknown>(key: string, initialValue?: T, options?: UseLocalStorageOptions<T>): UseStorageEngineReturn<T>;
1017
+ /**
1018
+ * Options accepted by `useSessionStorage`. Identical to
1019
+ * `BaseStorageOptions` — unlike `UseLocalStorageOptions`, there's no
1020
+ * `crossInstanceSync` option here, since sessionStorage isn't shared
1021
+ * across tabs in the first place.
1022
+ *
1023
+ * @typeParam T - The type of value being stored.
1024
+ */
1025
+ export type UseSessionStorageOptions<T> = BaseStorageOptions<T>;
1026
+ /**
1027
+ * Reads and writes a `sessionStorage` key, kept in sync with React state.
1028
+ *
1029
+ * - Scoped to the current tab: cleared when the tab closes, and not
1030
+ * shared with other tabs (unlike `useLocalStorage`).
1031
+ * - Stays in sync with every component in the current tab watching the
1032
+ * same key — see {@link UseSessionStorageOptions.sameInstanceSync}.
1033
+ * - Safe under SSR: on the server, and during the client's hydration
1034
+ * render, `value` is always `initialValue`. The real stored value is
1035
+ * only read client-side, immediately after hydration.
1036
+ *
1037
+ * @typeParam T - The type of value being stored. Defaults to `unknown` if
1038
+ * omitted — pass an explicit type argument for anything beyond ad-hoc use.
1039
+ * @param key - The `sessionStorage` key to read and write. Changing this
1040
+ * on a later render isn't supported; the hook warns (dev console +
1041
+ * `onError`) and keeps using the original key if you do.
1042
+ * @param initialValue - Used when nothing is stored yet, as the value
1043
+ * shown before hydration completes, and as what `removeValue` resets to.
1044
+ * @param options - See {@link UseSessionStorageOptions}.
1045
+ * @returns `{ value, setValue, removeValue, isHydrated, error }`.
1046
+ *
1047
+ * @example
1048
+ * ```tsx
1049
+ * const { value: draft, setValue: setDraft } = useSessionStorage("draft-comment", "");
1050
+ *
1051
+ * <textarea value={draft ?? ""} onChange={(e) => setDraft(e.target.value)} />
1052
+ * ```
1053
+ */
1054
+ export declare function useSessionStorage<T = unknown>(key: string, initialValue?: T, options?: UseSessionStorageOptions<T>): UseStorageEngineReturn<T>;
1055
+ /**
1056
+ * The default serializer used when no `serializer` option is passed to
1057
+ * `useLocalStorage`/`useSessionStorage`. Plain `JSON.stringify`/
1058
+ * `JSON.parse` — works for any JSON-safe value (objects, arrays, strings,
1059
+ * numbers, booleans, `null`), but not `Map`, `Set`, `Date`, `bigint`, or
1060
+ * `undefined` (see the other serializers below for those).
1061
+ */
494
1062
  export declare const defaultSerializer: StorageSerializer<unknown>;
1063
+ /**
1064
+ * Serializer for `Map` values. `JSON.stringify` can't handle `Map`
1065
+ * directly, so this round-trips it via an array of `[key, value]` entries.
1066
+ *
1067
+ * @typeParam K - The map's key type.
1068
+ * @typeParam V - The map's value type.
1069
+ *
1070
+ * @example
1071
+ * ```ts
1072
+ * useLocalStorage("tags", new Map<string, number>(), {
1073
+ * serializer: mapSerializer<string, number>(),
1074
+ * });
1075
+ * ```
1076
+ */
495
1077
  export declare function mapSerializer<K, V>(): StorageSerializer<Map<K, V>>;
1078
+ /**
1079
+ * Serializer for `Set` values, round-tripped via a plain array.
1080
+ *
1081
+ * @typeParam V - The set's value type.
1082
+ *
1083
+ * @example
1084
+ * ```ts
1085
+ * useLocalStorage("selectedIds", new Set<string>(), {
1086
+ * serializer: setSerializer<string>(),
1087
+ * });
1088
+ * ```
1089
+ */
496
1090
  export declare function setSerializer<V>(): StorageSerializer<Set<V>>;
1091
+ /**
1092
+ * Serializer for `Date` values, stored as an ISO 8601 string
1093
+ * (`Date.prototype.toISOString`).
1094
+ *
1095
+ * @throws During `deserialize`, if the stored string isn't a valid date —
1096
+ * caught by the hook, which falls back to `initialValue` and reports the
1097
+ * error via `onError`/the dev console warning.
1098
+ */
497
1099
  export declare const dateSerializer: StorageSerializer<Date>;
1100
+ /**
1101
+ * Serializer for `bigint` values. `JSON.stringify` throws on `bigint`
1102
+ * values, so this stores them as a plain decimal string instead.
1103
+ *
1104
+ * @throws During `deserialize`, if the stored string can't be converted to
1105
+ * a `bigint` — caught by the hook, which falls back to `initialValue` and
1106
+ * reports the error via `onError`/the dev console warning.
1107
+ */
498
1108
  export declare const bigIntSerializer: StorageSerializer<bigint>;
499
1109
  export interface FuzzyHighlighterProps {
500
1110
  text: string;
@@ -590,4 +1200,9 @@ export declare function useVisibility<T = unknown>(options?: {
590
1200
  initialVisibleIds?: VisibilityId[];
591
1201
  }): UseVisibilityReturn<T>;
592
1202
 
1203
+ export {
1204
+ UseStorageEngineReturn as UseLocalStorageReturn,
1205
+ UseStorageEngineReturn as UseSessionStorageReturn,
1206
+ };
1207
+
593
1208
  export {};