@bigbinary/neeto-commons-frontend 4.3.0 → 4.3.1

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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/react-utils.d.ts +1727 -159
  3. package/utils.d.ts +570 -95
package/react-utils.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import React, { ComponentType, ElementType, ReactNode } from "react";
2
-
3
- import { RouteProps, BrowserSupport } from "react-router-dom";
2
+ import { RouteProps } from "react-router-dom";
4
3
  import { Notice } from "@honeybadger-io/js/dist/server/types/core/types";
5
4
  import { History } from "history";
6
5
  import { StoreApi, UseBoundStore } from "zustand";
@@ -10,17 +9,112 @@ import { DefaultNamespace } from "react-i18next/TransWithoutContext";
10
9
  import { qsOptionsType, QueryParamsType } from "./utils";
11
10
  import { QueryFilters } from "react-query/types/core/utils";
12
11
  import BrowserSupport from "@bigbinary/neeto-molecules/types/BrowserSupport";
13
-
14
12
  type HoneybadgerErrorBoundaryPropsType = {
15
13
  ErrorComponent?: ReactNode | ComponentType | ElementType;
16
14
  filterErrors?: (error: Notice) => boolean;
17
15
  children?: ReactNode;
18
- }
16
+ };
19
17
  type BrowserSupportPropsType = React.ComponentProps<typeof BrowserSupport>;
18
+ /**
19
+ *
20
+ * The HoneybadgerErrorBoundary is an ErrorBoundary which reports frontend errors
21
+ *
22
+ * to HoneyBadger.
23
+ *
24
+ * This component will wrap its children with the error boundary provided by
25
+ *
26
+ * @honeybadger-io/react package. In this component, we will create a honeybadger
27
+ *
28
+ * configuration object using the API key, environment and project version which we
29
+ *
30
+ * obtained from the globalProps and pass the created object to error boundary
31
+ *
32
+ * provided by honeybadger. We are also filtering the false-positive errors using
33
+ *
34
+ * beforeNotify method.
35
+ *
36
+ * For global error handling, we need to wrap the Main component with this
37
+ *
38
+ * HoneybadgerErrorBoundary component as shown below.
39
+ *
40
+ * @example
41
+ *
42
+ * <HoneybadgerErrorBoundary
43
+ * ErrorComponent={ErrorComponent}
44
+ * filterErrors={notice => !/IgnorableError/.test(notice.message)}
45
+ * >
46
+ * <Main />
47
+ * </HoneybadgerErrorBoundary>
48
+ * @endexample
49
+ * ErrorComponent is the component which will be rendered when an error is thrown
50
+ *
51
+ * during rendering. This is an optional prop and if this prop is not provided then
52
+ *
53
+ * honeybadger will use DefaultErrorComponent for fallback UI.
54
+ *
55
+ * filterErrors is a function which takes the honeybadger notice as argument and
56
+ *
57
+ * returns a boolean. It should return true if the error is to be reported and
58
+ *
59
+ * false if not.
60
+ *
61
+ */
20
62
  export const HoneybadgerErrorBoundary: React.FC<HoneybadgerErrorBoundaryPropsType>;
63
+ /**
64
+ *
65
+ * The QueryClientProvider component wraps the application with a query client provider from @tanstack/react-query, facilitating data fetching and caching capabilities across the application using a predefined queryClient.
66
+ *
67
+ * @example
68
+ *
69
+ * import React from "react";
70
+ * import QueryClientProvider from "@bigbinary/neeto-commons-frontend/react-utils/QueryClientProvider";
71
+ *
72
+ * const App = () => (
73
+ * <QueryClientProvider>
74
+ * { Main application components }
75
+ * <MainComponent />
76
+ * </QueryClientProvider>
77
+ * );
78
+ *
79
+ * export default App;
80
+ * @endexample
81
+ */
21
82
  export const QueryClientProvider: React.FC<{
22
83
  children?: ReactNode;
23
84
  }>;
85
+ /**
86
+ *
87
+ * The AppContainer component serves as a wrapper around your main application components,it includes error handling with HoneybadgerErrorBoundary, browser support detection with BrowserSupport, client-side routing with BrowserRouter, query management with QueryClientProvider, and development tools with ReactQueryDevtools.
88
+ *
89
+ * @example
90
+ *
91
+ * import React from "react";
92
+ * import AppContainer from "@bigbinary/neeto-commons-frontend/react-utils/AppContainer";
93
+ *
94
+ * const App = () => (
95
+ * <AppContainer
96
+ * honeybadgerErrorBoundaryProps={{
97
+ * ErrorComponent: FallbackErrorComponent,
98
+ * filterErrors: (notice) => !/IgnorableError/.test(notice.message),
99
+ * }}
100
+ * browserSupportProps={{
101
+ * checkOnMount: true,
102
+ * unsupportedBrowserComponent: UnsupportedBrowserComponent,
103
+ * }}
104
+ * reactQueryDevtoolsProps={{
105
+ * initialIsOpen: true,
106
+ * position: "bottom-right",
107
+ * }}
108
+ * enableStickyRibbons={true}
109
+ * >
110
+ * { Main application components }
111
+ * <MainComponent />
112
+ * </AppContainer>
113
+ * );
114
+ *
115
+ * export default App;
116
+ * @endexample
117
+ */
24
118
  export const AppContainer: React.FC<{
25
119
  children?: ReactNode;
26
120
  honeybadgerErrorBoundaryProps?: HoneybadgerErrorBoundaryPropsType;
@@ -33,200 +127,1674 @@ export const AppContainer: React.FC<{
33
127
  };
34
128
  enableStickyRibbons?: boolean;
35
129
  }>;
36
-
37
- export function PrivateRoute(
38
- props: {
39
- condition?: boolean;
40
- redirectRoute?: string;
41
- errorPage?: React.ReactNode;
42
- permissions?: string[];
43
- } & RouteProps
44
- ): JSX.Element;
45
-
130
+ /**
131
+ *
132
+ * PrivateRoute is a route that will restrict access to it based on a specified
133
+ *
134
+ * condition and permissions.
135
+ *
136
+ * If the given condition is true and the user has the required permissions, it
137
+ *
138
+ * acts identical to a normal route. If the condition is true and the user does not
139
+ *
140
+ * have the required permissions, it will show 403 error page or it will render a
141
+ *
142
+ * supplied error page. If the condition is false, it will redirect user to a
143
+ *
144
+ * different path if redirectRoute is specified or it will render a supplied error
145
+ *
146
+ * page.
147
+ *
148
+ * If condition is not specified, it will assume the value of
149
+ *
150
+ * globalProps.authenticated by default.
151
+ *
152
+ * Here are some example use cases:
153
+ *
154
+ */
155
+ export function PrivateRoute(props: {
156
+ condition?: boolean;
157
+ redirectRoute?: string;
158
+ errorPage?: React.ReactNode;
159
+ permissions?: string[];
160
+ } & RouteProps): JSX.Element;
46
161
  type OptionsType = {
47
162
  root?: Element | null;
48
163
  rootMargin?: String;
49
164
  threshold?: Number | Number[];
50
165
  };
51
-
166
+ /**
167
+ *
168
+ * Component to set the page title.
169
+ *
170
+ * @example
171
+ *
172
+ * import React from "react";
173
+ * import PageTitle from "@bigbinary/neeto-molecules/PageTitle";
174
+ *
175
+ * const Page = () => (
176
+ * <Container>
177
+ * <PageTitle title="Login" />
178
+ * <div>Page content</div>
179
+ * </Container>
180
+ * );
181
+ * @endexample
182
+ */
52
183
  export const PageTitle: React.FC<{
53
184
  title?: string;
54
185
  }>;
55
-
56
- export function useIsElementVisibleInDom(
57
- target: Element | null,
58
- options?: OptionsType
59
- ): Boolean;
60
-
186
+ /**
187
+ *
188
+ * The useIsElementVisibleInDom hook is a utility that allows you to determine
189
+ *
190
+ * whether a target element is currently visible within the viewport or intersects
191
+ *
192
+ * with an ancestor element. In simpler terms, it helps you know when a specified
193
+ *
194
+ * element is scrolled out of or scrolled into the screen's visible area.
195
+ *
196
+ * The following code snippet demonstrates the usage of useIsElementVisibleInDom
197
+ *
198
+ * to display the heading element.
199
+ *
200
+ * @example
201
+ *
202
+ * import { useIsElementVisibleInDom } from "@bigbinary/neeto-commons-frontend/react-utils";
203
+ *
204
+ * const ref = useRef(null);
205
+ * const isHeadingWrapperVisible = useIsElementVisibleInDom(ref.current, {
206
+ * threshold: 0.5,
207
+ * });
208
+ *
209
+ * return (
210
+ * <div>
211
+ * <div style={{ height: "100vh" }}>
212
+ * <h1>Scroll down to next section</h1>
213
+ * </div>
214
+ * <div ref={ref}>
215
+ * {isHeadingWrapperVisible && <h1>Hello I'm on the screen</h1>}
216
+ * </div>
217
+ * </div>
218
+ * );
219
+ * @endexample
220
+ * The hook watches for changes in the visibility of the referenced div element
221
+ *
222
+ * and provides a boolean value that you can use to conditionally render the header
223
+ *
224
+ * element with the text Hello I'm on the screen.
225
+ *
226
+ */
227
+ export function useIsElementVisibleInDom(target: Element | null, options?: OptionsType): Boolean;
228
+ /**
229
+ *
230
+ * The useDebounce hook is a utility that allows you to wrap around a frequently
231
+ *
232
+ * updating state to retrieve the previous value until the updates are halted. This
233
+ *
234
+ * is particularly useful when you want to limit the number of API calls triggered
235
+ *
236
+ * by user inputs, such as a search box. The value returned by this hook will only
237
+ *
238
+ * reflect the latest value when the hook has not been called for the specified
239
+ *
240
+ * time period delay.
241
+ *
242
+ * The following code snippet demonstrates the usage of useDebounce in a search
243
+ *
244
+ * feature.
245
+ *
246
+ * @example
247
+ *
248
+ * import { useDebounce } from "@bigbinary/neeto-commons-frontend/react-utils";
249
+ *
250
+ * const [searchKey, setSearchKey] = useState("");
251
+ * const debouncedSearchKey = useDebounce(searchKey, 300);
252
+ *
253
+ * useEffect(() => {
254
+ * // will be triggered with the latest value of input
255
+ * // only after 300ms after the user stops typing
256
+ * }, [debouncedSearchKey]);
257
+ *
258
+ * // component
259
+ * <Input onChange={e => setSearchKey(e.target.value)} />;
260
+ * @endexample
261
+ * In the case of a search box, implemented without debouncing, every keystroke
262
+ *
263
+ * typically triggers a search query to find matching results. However, this rapid
264
+ *
265
+ * succession of queries can lead to several issues like performance overhead, poor
266
+ *
267
+ * user experience and inefficient resource usage.
268
+ *
269
+ * The useDebounce hook elegantly solves these problems by delaying the execution
270
+ *
271
+ * of the search function until the user pauses typing for a specified duration.
272
+ *
273
+ * This ensures that only one API request is made for the entire search operation,
274
+ *
275
+ * which solves all the issues mentioned earlier.
276
+ *
277
+ * You can learn more about the concept of debouncing
278
+ *
279
+ * here.
280
+ *
281
+ */
61
282
  export function useDebounce<T>(value: T, delay?: number): T;
62
-
63
- export function useFuncDebounce<F extends Function>(
64
- func: F,
65
- delay?: number
66
- ): F & { cancel: () => void };
67
-
68
- export function useLocalStorage<T>(
69
- key: string,
70
- initialValue?: T
71
- ): [T, (value: T) => void];
72
-
73
- export function useOnClickOutside<T>(
74
- ref: React.MutableRefObject<T>,
75
- handler: (event: MouseEvent | TouchEvent) => any,
76
- options: { enabled: boolean }
77
- );
78
-
283
+ /**
284
+ *
285
+ * The useFuncDebounce hook is a utility that extends the benefits of debouncing
286
+ *
287
+ * to functions.
288
+ *
289
+ * When the debounced function is called, it sets a timer to execute the original
290
+ *
291
+ * function after a specified delay. If the debounced function is called again
292
+ *
293
+ * before the timer expires, the previous timer is cleared. This effectively delays
294
+ *
295
+ * the execution of the original function until the debounced function hasn't been
296
+ *
297
+ * called for the specified delay period.
298
+ *
299
+ * The hook also provides a cancel method to manually cancel the execution of the
300
+ *
301
+ * debounced function before it triggers.
302
+ *
303
+ * The following code snippet demonstrates the usage of useFuncDebounce in the
304
+ *
305
+ * delaying the invocation of the fetch method until the user pauses typing for a
306
+ *
307
+ * specific period.
308
+ *
309
+ * @example
310
+ *
311
+ * import { useFuncDebounce } from "@bigbinary/neeto-commons-frontend/react-utils";
312
+ *
313
+ * const searchForProducts = useFuncDebounce(async key => {
314
+ * // this function will be triggered once after user stops typing for 300ms
315
+ * const products = await productsApi.fetch(key);
316
+ * // do something with the products
317
+ * }, 300);
318
+ *
319
+ * // component
320
+ * <Input onChange={e => searchForProducts(e.target.value)} />;
321
+ * <Button onClick={() => searchForProducts.cancel()}>Cancel search</Button>;
322
+ * @endexample
323
+ */
324
+ export function useFuncDebounce<F extends Function>(func: F, delay?: number): F & {
325
+ cancel: () => void;
326
+ };
327
+ /**
328
+ *
329
+ * The useLocalStorage hook is a utility for synchronizing and persisting state
330
+ *
331
+ * in the local storage of a web browser. It allows you to maintain data across
332
+ *
333
+ * page refreshes or even when the user navigates away from the page. This is
334
+ *
335
+ * useful for storing user preferences, settings, or any other data that should
336
+ *
337
+ * persist between sessions.
338
+ *
339
+ * To remove the value from local storage we can call the setter method with null
340
+ *
341
+ * or undefined.
342
+ *
343
+ * Note: Use this hook only if you need the component to re-render while
344
+ *
345
+ * updating the local storage value. If all you need is plain read and write
346
+ *
347
+ * operations on the localStorage, prefer the vanilla localStorage API functions.
348
+ *
349
+ * This hook will return an array with exactly two values just like useState
350
+ *
351
+ * hook.
352
+ *
353
+ * The following code snippet illustrates the usage of useLocalStorage in
354
+ *
355
+ * implementing a theme-switching feature.
356
+ *
357
+ * @example
358
+ *
359
+ * import { useLocalStorage } from "@bigbinary/neeto-commons-frontend/react-utils";
360
+ *
361
+ * // here "theme" is the storage key and "light" is the initial value
362
+ * const [theme, setTheme] = useLocalStorage("theme", "light");
363
+ *
364
+ * return (
365
+ * <Select
366
+ * options={[
367
+ * { label: "light", value: "light" },
368
+ * { label: "dark", value: "dark" },
369
+ * ]}
370
+ * // when we change the theme, the same will be stored in local storage with the key "theme"
371
+ * onChange={option => setTheme(option.value)}
372
+ * />
373
+ * );
374
+ * @endexample
375
+ * The initial value is used when the key is not found in local storage, ensuring
376
+ *
377
+ * that a default theme is applied when the user first visits the site. Subsequent
378
+ *
379
+ * changes to the theme are automatically synchronized with local storage.
380
+ *
381
+ * The following code snippet illustrates how we can pass a function to the
382
+ *
383
+ * setValue method of useLocalStorage
384
+ *
385
+ * @example
386
+ *
387
+ * import { useLocalStorage } from "@bigbinary/neeto-commons-frontend/react-utils";
388
+ * import { append } from "ramda";
389
+ *
390
+ * // here "hiddenColumns" is the storage key and "[]" is the initial value
391
+ * const [hiddenColumns, setHiddenColumns] = useLocalStorage("hiddenColumns", []);
392
+ *
393
+ * return (
394
+ * <Select
395
+ * options={[
396
+ * { label: "Name", value: "name" },
397
+ * { label: "Created at", value: "created_at" },
398
+ * ]}
399
+ * // when a new column to hide is selected, the same will be appended to the existing list of hidden columns and stored in local storage with the key "hiddenColumns"
400
+ * onChange={option => setHiddenColumns(append(option.value))}
401
+ * />
402
+ * );
403
+ * @endexample
404
+ */
405
+ export function useLocalStorage<T>(key: string, initialValue?: T): [T, (value: T) => void];
406
+ /**
407
+ *
408
+ * The useOnClickOutside hook is a useful utility for detecting clicks that occur
409
+ *
410
+ * outside of a specified element. It provides an elegant way to handle scenarios
411
+ *
412
+ * where you want to close or perform specific actions when a user clicks outside
413
+ *
414
+ * of a particular component, such as a modal dialog.
415
+ *
416
+ * The following code snippet demonstrates the usage of useOnClickOutside to
417
+ *
418
+ * detect clicks outside of a dropdown element and conditionally render the
419
+ *
420
+ * options.
421
+ *
422
+ * @example
423
+ *
424
+ * import { useOnClickOutside } from "@bigbinary/neeto-commons-frontend/react-utils";
425
+ *
426
+ * const Dropdown = () => {
427
+ * const dropdownRef = useRef(null);
428
+ * const [isDropdownOpen, setIsDropdownOpen] = useState(false);
429
+ *
430
+ * // Use the useOnClickOutside hook to close the dropdown when clicking outside of it
431
+ * useOnClickOutside(dropdownRef, () => setIsDropdownOpen(false));
432
+ *
433
+ * return (
434
+ * <div className="dropdown" ref={dropdownRef}>
435
+ * <button onClick={() => setIsDropdownOpen(!isDropdownOpen)}>
436
+ * Toggle Dropdown
437
+ * </button>
438
+ * {isDropdownOpen && (
439
+ * <ul className="dropdown-menu">
440
+ * <li>Option 1</li>
441
+ * <li>Option 2</li>
442
+ * <li>Option 3</li>
443
+ * </ul>
444
+ * )}
445
+ * </div>
446
+ * );
447
+ * };
448
+ * @endexample
449
+ */
450
+ export function useOnClickOutside<T>(ref: React.MutableRefObject<T>, handler: (event: MouseEvent | TouchEvent) => any, options: {
451
+ enabled: boolean;
452
+ });
453
+ /**
454
+ *
455
+ * The usePrevious hook is a convenient utility to track the previous value of
456
+ *
457
+ * its argument before its most recent update. When it is called for the first
458
+ *
459
+ * time, it returns the initial value passed as an argument, and subsequently, it
460
+ *
461
+ * returns the previous value every time the component re-renders.
462
+ *
463
+ * The hook can be useful in monitoring modifications to form fields, such as
464
+ *
465
+ * detecting when fields become dirty, and taking action based on these
466
+ *
467
+ * alterations.
468
+ *
469
+ * The following code snippet illustrates the usage of usePrevious in tracking
470
+ *
471
+ * which fields were modified in a form. By comparing the current and previous
472
+ *
473
+ * values of form fields, you can easily identify and handle changes without the
474
+ *
475
+ * need for complex state management.
476
+ *
477
+ * @example
478
+ *
479
+ * import { usePrevious } from "@bigbinary/neeto-commons-frontend/react-utils";
480
+ *
481
+ * // Initialize state for a form field (e.g., an input field)
482
+ * const [name, setName] = useState("");
483
+ *
484
+ * // Use the usePrevious hook to obtain the previous value of name
485
+ * const previousName = usePrevious(name);
486
+ *
487
+ * // Use useEffect to detect changes in the 'name' field
488
+ * useEffect(() => {
489
+ * // Check if the 'name' field has changed
490
+ * if (name !== previousName) {
491
+ * // The 'name' field has been modified
492
+ * // You can perform actions here, such as marking it as 'dirty'
493
+ * // or updating other parts of your application
494
+ * }
495
+ * }, [name]);
496
+ * @endexample
497
+ * In the example, the useEffect block listens for changes in the name field.
498
+ *
499
+ * When the name field is updated, it compares the current value to the previous
500
+ *
501
+ * value. If they differ, it signifies that the field has been modified, enabling
502
+ *
503
+ * you to take appropriate actions.
504
+ *
505
+ */
79
506
  export function usePrevious<T>(value: T): T;
80
-
507
+ /**
508
+ *
509
+ * The useUpdateEffect hook is a variation of the standard useEffect hook in
510
+ *
511
+ * React. The key difference is that useUpdateEffect does not execute the
512
+ *
513
+ * provided callback during the initial component mount. Instead, it only triggers
514
+ *
515
+ * the callback when the specified dependencies change. This behavior can be
516
+ *
517
+ * advantageous when you want to perform actions or side effects in response to
518
+ *
519
+ * changes in specific variables after the initial rendering of your component.
520
+ *
521
+ * The following code snippet shows the usage of useUpdateEffect in displaying
522
+ *
523
+ * category when its value is modified.
524
+ *
525
+ * @example
526
+ *
527
+ * import { useUpdateEffect } from "@bigbinary/neeto-commons-frontend/react-utils";
528
+ *
529
+ * // Initialize state variables
530
+ * const [category, setCategory] = useState("default");
531
+ *
532
+ * // Use useUpdateEffect to update content based on category changes
533
+ * useUpdateEffect(() => {
534
+ * // This callback will run when 'category' changes, but not during the initial mount
535
+ * console.log(`Category has been modified to ${category}`);
536
+ * }, [category]);
537
+ * @endexample
538
+ * The useUpdateEffect hook allows you to specify a callback function that will
539
+ *
540
+ * only execute when certain dependencies, in this case, the category state,
541
+ *
542
+ * change after the initial mount.
543
+ *
544
+ */
81
545
  export function useUpdateEffect(effect: () => void, deps: any[]): void;
82
-
546
+ /**
547
+ *
548
+ * The useDisplayErrorPage hook is a utility that allows you to conditionally
549
+ *
550
+ * render an error page in your application based on the status codes of API
551
+ *
552
+ * responses.
553
+ *
554
+ * The following code snippet demonstrates the usage of useDisplayErrorPage in
555
+ *
556
+ * conditionally rendering an error page.
557
+ *
558
+ * @example
559
+ *
560
+ * import { useDisplayErrorPage } from "@bigbinary/neeto-commons-frontend/react-utils";
561
+ *
562
+ * const App = () => {
563
+ * const isError = useDisplayErrorPage();
564
+ *
565
+ * if (isError) {
566
+ * return <ErrorPage />;
567
+ * }
568
+ *
569
+ * return <Main />;
570
+ * };
571
+ * @endexample
572
+ */
83
573
  export function useDisplayErrorPage(): boolean;
84
-
85
- export const useErrorDisplayStore: UseBoundStore<
86
- StoreApi<{
87
- showErrorPage: boolean;
88
- statusCode: number;
89
- failedApiUrl: string;
90
- failedApiPath: string;
91
- }>
92
- >;
93
-
574
+ /**
575
+ *
576
+ * A Zustand store containing the status code of the latest API failed with 403 or
577
+ *
578
+ * 404 status. It stores the following values:
579
+ *
580
+ * This store is automatically managed by neeto-commons-frontend using its axios
581
+ *
582
+ * interceptors. You can also use this store if you need to display an error page
583
+ *
584
+ * from your frontend logic.
585
+ *
586
+ */
587
+ export const useErrorDisplayStore: UseBoundStore<StoreApi<{
588
+ showErrorPage: boolean;
589
+ statusCode: number;
590
+ failedApiUrl: string;
591
+ failedApiPath: string;
592
+ }>>;
94
593
  type TimerType = {
95
594
  lastUpdated: number;
96
595
  interval: number;
97
596
  };
597
+ /**
598
+ *
599
+ * The useTimer hook is a utility that enables automatic re-renders of a
600
+ *
601
+ * component at specified time intervals. This functionality is particularly useful
602
+ *
603
+ * for updating rendered content, such as elapsed time, without requiring manual
604
+ *
605
+ * refreshes.
606
+ *
607
+ * All invocations of useTimer hooks are attached to a single setInterval call
608
+ *
609
+ * which ticks every 1 second. So using that hook in multiple components won't
610
+ *
611
+ * cause any performance drop.
612
+ *
613
+ * Note that the maximum precision for useTimer hook is one second. In other
614
+ *
615
+ * words, there is a possibility that your component will take at most one more
616
+ *
617
+ * second than the scheduled time interval to re-render.
618
+ *
619
+ * The following demonstrates the usage of useTimer hook in displaying
620
+ *
621
+ * time-sensitive information.
622
+ *
623
+ * @example
624
+ *
625
+ * import { useTimer } from "@bigbinary/neeto-commons-frontend/react-utils";
626
+ *
627
+ * const Post = () => {
628
+ * // Use the useTimer hook with a custom interval
629
+ * useTimer(30);
630
+ *
631
+ * // Calculate the elapsed time since the post creation
632
+ * const currentTime = new Date();
633
+ * const elapsedTimeInSeconds = Math.floor((currentTime - createdAt) / 1000);
634
+ *
635
+ * return <p>Elapsed Time in seconds: {elapsedTimeInSeconds}</p>;
636
+ * };
637
+ * @endexample
638
+ */
98
639
  export function useTimer(interval: number): TimerType;
99
-
100
- type ZustandConfigType = (
101
- set: (data: any) => void,
102
- get: () => any,
103
- api: any
104
- ) => any;
105
- export function withImmutableActions(
106
- config: ZustandConfigType
107
- ): ZustandConfigType;
108
-
640
+ type ZustandConfigType = (set: (data: any) => void, get: () => any, api: any) => any;
641
+ /**
642
+ *
643
+ * withImmutableActions is a Zustand middleware function that prevents the
644
+ *
645
+ * actions from getting overwritten.
646
+ *
647
+ * @example
648
+ *
649
+ * const useStore = create(
650
+ * withImmutableActions(set => ({
651
+ * value: 10,
652
+ * // other properties ...
653
+ * setValue: ({ value }) => set({ value }),
654
+ * setGlobalState: set,
655
+ * // other actions ...
656
+ * }))
657
+ * );
658
+ * @endexample
659
+ * In the example above, any attempts like the following will trigger an error
660
+ *
661
+ * because actions should never be overwritten:
662
+ *
663
+ * @example
664
+ *
665
+ * setGlobalState({ value: 0, setValue: () => {} });
666
+ * @endexample
667
+ * However, actions can be assigned their own values. This enables you to use
668
+ *
669
+ * curried Ramda functions in conjunction with Zustand actions. For instance, the
670
+ *
671
+ * following usage will not result in an error:
672
+ *
673
+ * @example
674
+ *
675
+ * setGlobalState(state => ({ value: 0, setValue: state.setValue }));
676
+ * @endexample
677
+ * The second parameter to overwrite the entire state will be ignored. Both of the
678
+ *
679
+ * following lines of code are functionally equivalent:
680
+ *
681
+ * @example
682
+ *
683
+ * setGlobalState(state => ({ value: 0 }), true);
684
+ * setGlobalState(state => ({ value: 0 }));
685
+ * @endexample
686
+ * It should be noted that the withImmutableActions middleware intercepts and
687
+ *
688
+ * wraps the set method of the Zustand store to enforce immutability rules.
689
+ *
690
+ * Therefore, usages of useStore.setState() won't be handled by the middleware
691
+ *
692
+ * since they directly update the state in Zustand without going through the set
693
+ *
694
+ * method of the store.
695
+ *
696
+ * @example
697
+ *
698
+ * // This won't be handled by the middleware.
699
+ * useStore.setState({ value: 0, setValue: () => {} });
700
+ * @endexample
701
+ */
702
+ export function withImmutableActions(config: ZustandConfigType): ZustandConfigType;
109
703
  export declare type ZustandStoreHook = UseBoundStore<StoreApi<any>> & {
110
704
  pick: (path?: string | string[]) => any;
111
705
  };
112
-
706
+ /**
707
+ *
708
+ * The useFieldSubmit hook simplifies the task of capturing the Enter
709
+ *
710
+ * (Return) key press event within an input field and executing a callback
711
+ *
712
+ * function when the Enter key is pressed. This is a common requirement in forms
713
+ *
714
+ * where pressing Enter should trigger specific actions, such as submitting a
715
+ *
716
+ * form or processing user input. Importantly, this hook ensures that pressing
717
+ *
718
+ * Shift + Enter does not trigger the callback, allowing for the creation of
719
+ *
720
+ * multi-line text inputs.
721
+ *
722
+ * The following code snippet illustrates the usage of useFieldSubmit in building
723
+ *
724
+ * an interactive textarea input field.
725
+ *
726
+ * @example
727
+ *
728
+ * import { useFieldSubmit } from "@bigbinary/neeto-commons-frontend/react-utils";
729
+ *
730
+ * // Create a ref for the input field using useFieldSubmit
731
+ * const inputRef = useFieldSubmit(() => {
732
+ * const inputValue = inputRef.current.value;
733
+ * console.log(inputValue);
734
+ * });
735
+ *
736
+ * return <textarea ref={inputRef} />;
737
+ * @endexample
738
+ * When the Enter key is pressed, the onSubmit callback function is executed,
739
+ *
740
+ * allowing you to access the input value and perform the desired action.
741
+ *
742
+ */
113
743
  export function useFieldSubmit(onSubmit: () => any): {
114
744
  current: HTMLInputElement & HTMLTextAreaElement;
115
745
  };
116
-
117
- export function withTitle<T>(
118
- Component: React.ComponentType<T>,
119
- title?: string | null
120
- ): (props: T) => JSX.Element;
121
-
746
+ /**
747
+ *
748
+ * withTitle is an HOC which sets the browser title with the given value when the
749
+ *
750
+ * wrapped component is rendered. If title is not explicitly provided, it will
751
+ *
752
+ * render globalProps.appName as the page title.
753
+ *
754
+ * @example
755
+ *
756
+ * // assume this code in neetoStore
757
+ * const ProductsPage = props => <>Your page content here</>;
758
+ *
759
+ * // will set the browser title to `All products | neetoStore` when this page is rendered.
760
+ * export default withTitle(ProductsPage, "All products");
761
+ * @endexample
762
+ */
763
+ export function withTitle<T>(Component: React.ComponentType<T>, title?: string | null): (props: T) => JSX.Element;
764
+ /**
765
+ *
766
+ * registerBrowserNotifications is a browser push notifications utility function
767
+ *
768
+ * which asks the user permissions to send notifications and then register the
769
+ *
770
+ * browser with the notification service.
771
+ *
772
+ * To enable the notification service to dispatch web push messages to browsers, it
773
+ *
774
+ * relies on VAPID keys. These
775
+ *
776
+ * keys should be securely stored as environment variables and made accessible
777
+ *
778
+ * through process.env. If keys are not accessible from process.env, pass in
779
+ *
780
+ * the vapidPublicKey using global props from application helper.
781
+ *
782
+ * You can find the VAPID keys (PUBLIC and PRIVATE) for neeto products at
783
+ *
784
+ * neetoNotifications Dashboard.
785
+ *
786
+ * After the user logs in, we need to ask the user permissions to send
787
+ *
788
+ * notifications and then register the browser with the notification service. The
789
+ *
790
+ * registerBrowserNotifications utility function facilitates this process. It can
791
+ *
792
+ * be called on any event after login based on the application's logic and
793
+ *
794
+ * requirement.
795
+ *
796
+ * Here as an example, we are calling registerBrowserNotifications method inside
797
+ *
798
+ * the Login component after the Authentication API request. This helps to
799
+ *
800
+ * associate the browser for that particular user.
801
+ *
802
+ * @example
803
+ *
804
+ * import { registerBrowserNotifications } from "neetocommons/react-utils";
805
+ *
806
+ * const handleLogin = async () => {
807
+ * try {
808
+ * // Authentication API request
809
+ * await registerBrowserNotifications();
810
+ * history.push(DASHBOARD_URL);
811
+ * } catch {}
812
+ * };
813
+ * @endexample
814
+ * The above mentioned feature is currently supported for chromium-based browsers.
815
+ *
816
+ * Safari (iOS) is currently WIP.
817
+ *
818
+ * Any other browser which is not mentioned in above will be considered as
819
+ *
820
+ * unsupported.
821
+ *
822
+ */
122
823
  export async function registerBrowserNotifications(): Promise<void>;
123
-
824
+ /**
825
+ *
826
+ * destroyBrowserSubscription is a browser push notifications utility function
827
+ *
828
+ * which destroys the browser subscriptions from the user's devices. This helps in
829
+ *
830
+ * unsubscribing from browser push notifications.
831
+ *
832
+ * When the browser subscriptions expires for the user's devices or when the user
833
+ *
834
+ * decides to logout, the generated browser subscription for the user should be
835
+ *
836
+ * destroyed. The destroyBrowserSubscription utility function enables us to do
837
+ *
838
+ * the same. It can be called on any event before logout based on the application's
839
+ *
840
+ * logic and requirement.
841
+ *
842
+ * Here is an example: In the Logout component, we are calling
843
+ *
844
+ * destroyBrowserSubscription method before the Logout API request. This
845
+ *
846
+ * helps to destroy the browser subscription from the user's devices.
847
+ *
848
+ * @example
849
+ *
850
+ * import { destroyBrowserSubscription } from "neetocommons/react-utils";
851
+ *
852
+ * const handleLogout = async () => {
853
+ * try {
854
+ * await destroyBrowserSubscription(); //Before logout request
855
+ * // Logout API request
856
+ * window.location.href = LOGIN_PATH;
857
+ * } catch {}
858
+ * };
859
+ * @endexample
860
+ * The above mentioned feature is currently supported for chromium-based browsers.
861
+ *
862
+ * Safari (iOS) is currently WIP.
863
+ *
864
+ * Any other browser which is not mentioned in above will be considered as
865
+ *
866
+ * unsupported.
867
+ *
868
+ */
124
869
  export async function destroyBrowserSubscription(): Promise<void>;
125
-
126
870
  type handleMetaClickOptions = {
127
- isHistoryReplace?: boolean
128
- }
129
- export function handleMetaClick(
130
- history: History,
131
- params: string | object,
132
- event: React.MouseEvent<HTMLElement, MouseEvent>,
133
- options?: handleMetaClickOptions
134
- ): void;
135
- export function handleMetaClick(
136
- history: History,
137
- params: string | object,
138
- event: React.MouseEvent<HTMLElement, MouseEvent>,
139
- ): (options?: handleMetaClickOptions) => void;
140
- export function handleMetaClick(
141
- history: History,
142
- params: string | object
143
- ): (
144
- event: React.MouseEvent<HTMLElement, MouseEvent>,
145
- options?: handleMetaClickOptions
146
- ) => void;
147
- export function handleMetaClick(
148
- history: History
149
- ): (
150
- params: string | object,
151
- event: React.MouseEvent<HTMLElement, MouseEvent>,
152
- options?: handleMetaClickOptions
153
- ) => void;
154
-
155
- export function isMetaKeyPressed(
156
- event: React.MouseEvent<HTMLElement, MouseEvent>
157
- ): boolean;
158
-
159
- export function useStateWithDependency<T>(
160
- defaultValue: T,
161
- dependencies?: any[]
162
- ): T;
163
-
164
- export function useRegisterNavigationCheckpoint(
165
- key: string,
166
- path?: string,
167
- persistInLocalStorage?: boolean
168
- ): void;
169
-
871
+ isHistoryReplace?: boolean;
872
+ };
873
+ /**
874
+ *
875
+ * The handleMetaClick function can be used to handle onClick actions that
876
+ *
877
+ * redirects to a URL. It opens up the URL in a new tab if ctrl/cmd + click event
878
+ *
879
+ * is received. Otherwise, simply redirects to the provided URL in the same tab.
880
+ *
881
+ * URL can be passed as string or a history location object can be passed instead.
882
+ *
883
+ * Let's say you have a navigation menu with several links, and you want to allow
884
+ *
885
+ * users to open these links in a new tab if they hold down the Ctrl (or Cmd on
886
+ *
887
+ * macOS) key while clicking, and if they click without holding down the Ctrl key,
888
+ *
889
+ * the link should open in the same tab. You can use handleMetaClick to achieve
890
+ *
891
+ * this behavior.
892
+ *
893
+ * @example
894
+ *
895
+ * const NavigationMenu = () => {
896
+ * const history = useHistory();
897
+ *
898
+ * const handleLinkClick = (url, event) => {
899
+ * // Opens url in a new tab if metaKey/CtrlKey is pressed.
900
+ * // Otherwise simply redirects to url.
901
+ * handleMetaClick(history, url, event);
902
+ * };
903
+ *
904
+ * return (
905
+ * <div>
906
+ * <a href="/home" onClick={e => handleLinkClick("/home", e)}>
907
+ * Home
908
+ * </a>
909
+ * <a href="/dashboard" onClick={e => handleLinkClick("/dashboard", e)}>
910
+ * Dashboard
911
+ * </a>
912
+ * <a href="/profile" onClick={e => handleLinkClick("/profile", e)}>
913
+ * Profile
914
+ * </a>
915
+ * </div>
916
+ * );
917
+ * };
918
+ * @endexample
919
+ */
920
+ export function handleMetaClick(history: History, params: string | object, event: React.MouseEvent<HTMLElement, MouseEvent>, options?: handleMetaClickOptions): void;
921
+ /**
922
+ *
923
+ * The handleMetaClick function can be used to handle onClick actions that
924
+ *
925
+ * redirects to a URL. It opens up the URL in a new tab if ctrl/cmd + click event
926
+ *
927
+ * is received. Otherwise, simply redirects to the provided URL in the same tab.
928
+ *
929
+ * URL can be passed as string or a history location object can be passed instead.
930
+ *
931
+ * Let's say you have a navigation menu with several links, and you want to allow
932
+ *
933
+ * users to open these links in a new tab if they hold down the Ctrl (or Cmd on
934
+ *
935
+ * macOS) key while clicking, and if they click without holding down the Ctrl key,
936
+ *
937
+ * the link should open in the same tab. You can use handleMetaClick to achieve
938
+ *
939
+ * this behavior.
940
+ *
941
+ * @example
942
+ *
943
+ * const NavigationMenu = () => {
944
+ * const history = useHistory();
945
+ *
946
+ * const handleLinkClick = (url, event) => {
947
+ * // Opens url in a new tab if metaKey/CtrlKey is pressed.
948
+ * // Otherwise simply redirects to url.
949
+ * handleMetaClick(history, url, event);
950
+ * };
951
+ *
952
+ * return (
953
+ * <div>
954
+ * <a href="/home" onClick={e => handleLinkClick("/home", e)}>
955
+ * Home
956
+ * </a>
957
+ * <a href="/dashboard" onClick={e => handleLinkClick("/dashboard", e)}>
958
+ * Dashboard
959
+ * </a>
960
+ * <a href="/profile" onClick={e => handleLinkClick("/profile", e)}>
961
+ * Profile
962
+ * </a>
963
+ * </div>
964
+ * );
965
+ * };
966
+ * @endexample
967
+ */
968
+ export function handleMetaClick(history: History, params: string | object, event: React.MouseEvent<HTMLElement, MouseEvent>): (options?: handleMetaClickOptions) => void;
969
+ /**
970
+ *
971
+ * The handleMetaClick function can be used to handle onClick actions that
972
+ *
973
+ * redirects to a URL. It opens up the URL in a new tab if ctrl/cmd + click event
974
+ *
975
+ * is received. Otherwise, simply redirects to the provided URL in the same tab.
976
+ *
977
+ * URL can be passed as string or a history location object can be passed instead.
978
+ *
979
+ * Let's say you have a navigation menu with several links, and you want to allow
980
+ *
981
+ * users to open these links in a new tab if they hold down the Ctrl (or Cmd on
982
+ *
983
+ * macOS) key while clicking, and if they click without holding down the Ctrl key,
984
+ *
985
+ * the link should open in the same tab. You can use handleMetaClick to achieve
986
+ *
987
+ * this behavior.
988
+ *
989
+ * @example
990
+ *
991
+ * const NavigationMenu = () => {
992
+ * const history = useHistory();
993
+ *
994
+ * const handleLinkClick = (url, event) => {
995
+ * // Opens url in a new tab if metaKey/CtrlKey is pressed.
996
+ * // Otherwise simply redirects to url.
997
+ * handleMetaClick(history, url, event);
998
+ * };
999
+ *
1000
+ * return (
1001
+ * <div>
1002
+ * <a href="/home" onClick={e => handleLinkClick("/home", e)}>
1003
+ * Home
1004
+ * </a>
1005
+ * <a href="/dashboard" onClick={e => handleLinkClick("/dashboard", e)}>
1006
+ * Dashboard
1007
+ * </a>
1008
+ * <a href="/profile" onClick={e => handleLinkClick("/profile", e)}>
1009
+ * Profile
1010
+ * </a>
1011
+ * </div>
1012
+ * );
1013
+ * };
1014
+ * @endexample
1015
+ */
1016
+ export function handleMetaClick(history: History, params: string | object): (event: React.MouseEvent<HTMLElement, MouseEvent>, options?: handleMetaClickOptions) => void;
1017
+ /**
1018
+ *
1019
+ * The handleMetaClick function can be used to handle onClick actions that
1020
+ *
1021
+ * redirects to a URL. It opens up the URL in a new tab if ctrl/cmd + click event
1022
+ *
1023
+ * is received. Otherwise, simply redirects to the provided URL in the same tab.
1024
+ *
1025
+ * URL can be passed as string or a history location object can be passed instead.
1026
+ *
1027
+ * Let's say you have a navigation menu with several links, and you want to allow
1028
+ *
1029
+ * users to open these links in a new tab if they hold down the Ctrl (or Cmd on
1030
+ *
1031
+ * macOS) key while clicking, and if they click without holding down the Ctrl key,
1032
+ *
1033
+ * the link should open in the same tab. You can use handleMetaClick to achieve
1034
+ *
1035
+ * this behavior.
1036
+ *
1037
+ * @example
1038
+ *
1039
+ * const NavigationMenu = () => {
1040
+ * const history = useHistory();
1041
+ *
1042
+ * const handleLinkClick = (url, event) => {
1043
+ * // Opens url in a new tab if metaKey/CtrlKey is pressed.
1044
+ * // Otherwise simply redirects to url.
1045
+ * handleMetaClick(history, url, event);
1046
+ * };
1047
+ *
1048
+ * return (
1049
+ * <div>
1050
+ * <a href="/home" onClick={e => handleLinkClick("/home", e)}>
1051
+ * Home
1052
+ * </a>
1053
+ * <a href="/dashboard" onClick={e => handleLinkClick("/dashboard", e)}>
1054
+ * Dashboard
1055
+ * </a>
1056
+ * <a href="/profile" onClick={e => handleLinkClick("/profile", e)}>
1057
+ * Profile
1058
+ * </a>
1059
+ * </div>
1060
+ * );
1061
+ * };
1062
+ * @endexample
1063
+ */
1064
+ export function handleMetaClick(history: History): (params: string | object, event: React.MouseEvent<HTMLElement, MouseEvent>, options?: handleMetaClickOptions) => void;
1065
+ /**
1066
+ *
1067
+ * The isMetaKeyPressed function can be used to check whether an onClick event
1068
+ *
1069
+ * has metaKey or ctrlKey pressed.
1070
+ *
1071
+ * @example
1072
+ *
1073
+ * isMetaKeyPressed(event);
1074
+ * @endexample
1075
+ */
1076
+ export function isMetaKeyPressed(event: React.MouseEvent<HTMLElement, MouseEvent>): boolean;
1077
+ /**
1078
+ *
1079
+ * The useStateWithDependency hook is a utility that returns a state variable and
1080
+ *
1081
+ * a setter function similar to the useState hook. However, it provides
1082
+ *
1083
+ * additional functionality: the state variable automatically updates its value to
1084
+ *
1085
+ * the specified defaultValue whenever defaultValue changes. Optionally, you
1086
+ *
1087
+ * can also specify a dependencies array to listen for changes in other variables,
1088
+ *
1089
+ * which will trigger the update of the state variable.
1090
+ *
1091
+ * This hook will return an array with exactly two values just like useState
1092
+ *
1093
+ * hook.
1094
+ *
1095
+ * If dependencies is passed, the hook returns a state variable whose value will
1096
+ *
1097
+ * be updated to defaultValue in a useEffect that depends on the dependencies
1098
+ *
1099
+ * array. Otherwise, the useEffect will depend only on the defaultValue.
1100
+ *
1101
+ * @example
1102
+ *
1103
+ * import { useStateWithDependency } from "@bigbinary/neeto-commons-frontend/react-utils";
1104
+ *
1105
+ * // reset state to `defaultValue` whenever `defaultValue` changes.
1106
+ * const [value, setValue] = useStateWithDependency(defaultValue);
1107
+ *
1108
+ * // reset state to `defaultValue` only when `value1` or `value2` changes.
1109
+ * const [value, setValue] = useStateWithDependency(defaultValue, [
1110
+ * value1,
1111
+ * value2,
1112
+ * ]);
1113
+ *
1114
+ * // In a case, where the value needs to be reset when defaultValue
1115
+ * // changes too, defaultValue can be passed with the dependencies,
1116
+ * // as shown below.
1117
+ * const [value, setValue] = useStateWithDependency(defaultValue, [
1118
+ * value1,
1119
+ * value2,
1120
+ * defaultValue,
1121
+ * ]);
1122
+ * @endexample
1123
+ * The following code snippet demonstrates the usage of useStateWithDependency in
1124
+ *
1125
+ * ensuring that inputValue stays in sync with the value prop in the Rename
1126
+ *
1127
+ * component.
1128
+ *
1129
+ * @example
1130
+ *
1131
+ * const Rename = ({ value }) => {
1132
+ * // Use the useStateWithDependency hook to manage the input value
1133
+ * const [inputValue, setInputValue] = useStateWithDependency(value);
1134
+ *
1135
+ * // Define a handler to update the input value
1136
+ * const handleInputChange = event => {
1137
+ * setInputValue(event.target.value);
1138
+ * };
1139
+ *
1140
+ * return (
1141
+ * <div>
1142
+ * <input type="text" value={inputValue} onChange={handleInputChange} />
1143
+ * { Rest of the component }
1144
+ * </div>
1145
+ * );
1146
+ * };
1147
+ * @endexample
1148
+ * As the user interacts with the input field, the inputValue state is updated to
1149
+ *
1150
+ * reflect the user's input. In a scenario where the value prop changes from
1151
+ *
1152
+ * outside the Rename component, it triggers a re-render of the Rename
1153
+ *
1154
+ * component. When this re-render occurs, the inputValue state is automatically
1155
+ *
1156
+ * updated to match the new value prop.
1157
+ *
1158
+ */
1159
+ export function useStateWithDependency<T>(defaultValue: T, dependencies?: any[]): T;
1160
+ /**
1161
+ *
1162
+ * The useRegisterNavigationCheckpoint hook is a utility for storing navigation
1163
+ *
1164
+ * checkpoints in a Zustand store. A navigation checkpoint consists of a key that
1165
+ *
1166
+ * identifies the checkpoint and a corresponding path to be stored in the Zustand
1167
+ *
1168
+ * store under that key. These registered checkpoints can be later retrieved using
1169
+ *
1170
+ * the useNavigationCheckpoints hook.
1171
+ *
1172
+ * In web applications, scenarios frequently arise where it's essential to maintain
1173
+ *
1174
+ * user preferences and specific application states as users navigate back and
1175
+ *
1176
+ * forth between different routes.
1177
+ *
1178
+ * A simple button, that hard codes the route as <Link to="/resource" />, won't
1179
+ *
1180
+ * suffice in such scenarios to navigate between pages since it won't retain any
1181
+ *
1182
+ * filter, search, or pagination information.
1183
+ *
1184
+ * This is why we have checkpoints. When a page component is mounted, a checkpoint
1185
+ *
1186
+ * is registered to capture the current state of the page, including the URL with
1187
+ *
1188
+ * applied filters, search parameters, and pagination information. If the URL
1189
+ *
1190
+ * changes due to user interactions, the checkpoint is automatically updated.
1191
+ *
1192
+ * When a user presses the back button, the value stored in the checkpoint is used
1193
+ *
1194
+ * as the URL. This ensures that users return to the listing page with all their
1195
+ *
1196
+ * previous context intact, providing a seamless and user-friendly experience.
1197
+ *
1198
+ * Following code snippet illustrates the usage of
1199
+ *
1200
+ * useRegisterNavigationCheckpoint in retaining user preference and context.
1201
+ *
1202
+ * @example
1203
+ *
1204
+ * // Import the useRegisterNavigationCheckpoint hook
1205
+ * import { useRegisterNavigationCheckpoint } from "@bigbinary/neeto-commons-frontend/react-utils";
1206
+ * // ...
1207
+ *
1208
+ * // Register a navigation checkpoint with a key and path
1209
+ * useRegisterNavigationCheckpoint(
1210
+ * NAVIGATION_CHECKPOINT_KEYS.ARTICLES,
1211
+ * window.location.pathname + window.location.search
1212
+ * );
1213
+ * @endexample
1214
+ * When users visit the articles page, apply specific filters, and navigate away,
1215
+ *
1216
+ * the navigation checkpoint captures the current URL path along with the query
1217
+ *
1218
+ * parameters associated with the applied filters. Later, when users return to the
1219
+ *
1220
+ * page, the useNavigationCheckpoints hook can retrieve the saved checkpoint
1221
+ *
1222
+ * using the NAVIGATION_CHECKPOINT_KEYS.ARTICLES key. This retrieved data
1223
+ *
1224
+ * includes the applied filters, which can then be displayed on the articles page.
1225
+ *
1226
+ * It is worth noting that, at BigBinary, we define the object
1227
+ *
1228
+ * NAVIGATION_CHECKPOINT_KEYS to store the check point keys like so:
1229
+ *
1230
+ * @example
1231
+ *
1232
+ * export const NAVIGATION_CHECKPOINT_KEYS = {
1233
+ * HOME: "home",
1234
+ * ARTICLES: "articles",
1235
+ * };
1236
+ * @endexample
1237
+ */
1238
+ export function useRegisterNavigationCheckpoint(key: string, path?: string, persistInLocalStorage?: boolean): void;
1239
+ /**
1240
+ *
1241
+ * The useNavigationCheckpoints hook is a convenient tool for fetching designated
1242
+ *
1243
+ * navigation checkpoints stored in a Zustand store.
1244
+ *
1245
+ * In web applications, users frequently move between various pages or routes, and
1246
+ *
1247
+ * useRegisterNavigationCheckpoint empowers us to store particular paths or
1248
+ *
1249
+ * states as checkpoints. By employing the useNavigationCheckpoints hook, you can
1250
+ *
1251
+ * access these checkpoints by specifying their associated keys.
1252
+ *
1253
+ * We recommend reviewing the documentation for the
1254
+ *
1255
+ * useRegisterNavigationCheckpoint hook to
1256
+ *
1257
+ * gain a deeper understanding of the checkpoint concept.
1258
+ *
1259
+ * The following code snippet demonstrates the usage of useNavigationCheckpoints
1260
+ *
1261
+ * in retrieving navigation links that reflect the application's state and history.
1262
+ *
1263
+ * @example
1264
+ *
1265
+ * // Import the useNavigationCheckpoints hook
1266
+ * import { useNavigationCheckpoints } from "@bigbinary/neeto-commons-frontend/react-utils";
1267
+ *
1268
+ * const navigationCheckpoints = useNavigationCheckpoints("home");
1269
+ *
1270
+ * return (
1271
+ * <>
1272
+ * <Link to={navigationCheckpoints["home"]}>Home</Link>
1273
+ * </>
1274
+ * );
1275
+ * @endexample
1276
+ * The above code fetches navigation checkpoint data for the home key using the
1277
+ *
1278
+ * useNavigationCheckpoints hook and then renders a link labeled "Home" that,
1279
+ *
1280
+ * when clicked, will navigate the user to the URL associated with the home
1281
+ *
1282
+ * navigation checkpoint.
1283
+ *
1284
+ */
170
1285
  export function useNavigationCheckpoints(...keys: string[]): {
171
1286
  [key: string]: string;
172
1287
  };
173
-
174
- export function useRemoveNavigationCheckpoint():(key:string)=>void;
175
-
1288
+ /**
1289
+ *
1290
+ * The useRemoveNavigationCheckpoint hook is a utility for removing a navigation
1291
+ *
1292
+ * checkpoint from the navigation checkpoints stored in the Zustand store.
1293
+ *
1294
+ * In web applications, users frequently move between various pages or routes, and
1295
+ *
1296
+ * useRegisterNavigationCheckpoint empowers us to store particular paths or
1297
+ *
1298
+ * states as checkpoints. By employing the useNavigationCheckpoints hook, you can
1299
+ *
1300
+ * access these checkpoints by specifying their associated keys. There might arise
1301
+ *
1302
+ * a case where you want to remove a particular checkpoint from the Zustand store,
1303
+ *
1304
+ * useRemoveNavigationCheckpoint can be used for this.
1305
+ *
1306
+ * We recommend reviewing the documentation for the
1307
+ *
1308
+ * useRegisterNavigationCheckpoint and useNavigationCheckpoints hooks for
1309
+ *
1310
+ * gaining a deeper understanding of the checkpoint concept.
1311
+ *
1312
+ * The following code snippet demonstrates the usage of
1313
+ *
1314
+ * useRemoveNavigationCheckpoint in removing a navigation checkpoint from the
1315
+ *
1316
+ * Zustand store.
1317
+ *
1318
+ * @example
1319
+ *
1320
+ * // Import the useRemoveNavigationCheckpoint hook
1321
+ * import { useRemoveNavigationCheckpoint } from "@bigbinary/neeto-commons-frontend/react-utils";
1322
+ *
1323
+ * const removeCheckpoint = useRemoveNavigationCheckpoint();
1324
+ *
1325
+ * removeCheckpoint("home");
1326
+ * @endexample
1327
+ * The above code removes the navigation checkpoint corresponding to the home key
1328
+ *
1329
+ * using the useRemoveNavigationCheckpoint hook.
1330
+ *
1331
+ */
1332
+ export function useRemoveNavigationCheckpoint(): (key: string) => void;
1333
+ /**
1334
+ *
1335
+ * The useRestoreScrollPosition hook facilitates the restoration and synchronization of scroll positions for components using Zustand store.
1336
+ *
1337
+ * Maintaining scroll positions as users navigate between different routes or interact with dynamic content is crucial for preserving user context and enhancing usability. useRestoreScrollPosition addresses this by allowing components to save and restore scroll positions based on specified keys.
1338
+ *
1339
+ * Here's an example demonstrating how to use useRestoreScrollPosition to manage scroll positions within a React component:
1340
+ *
1341
+ * @example
1342
+ *
1343
+ * import React, { useRef } from "react";
1344
+ * import useRestoreScrollPosition, { useRemoveScrollPosition } from "@bigbinary/neeto-commons-frontend/react-utils/useRestoreScrollPosition";
1345
+ *
1346
+ * const ScrollableComponent = ({ scrollKey }) => {
1347
+ * const ref = useRef(null);
1348
+ *
1349
+ * // Hook to manage scroll position restoration
1350
+ * useRestoreScrollPosition(scrollKey, ref);
1351
+ *
1352
+ * // Example of how to remove a saved scroll position
1353
+ * const removeScrollPosition = useRemoveScrollPosition();
1354
+ * const handleClearScrollPosition = () => {
1355
+ * removeScrollPosition(scrollKey);
1356
+ * };
1357
+ *
1358
+ * return (
1359
+ * <div {...{ ref }}>
1360
+ * { Scrollable content }
1361
+ * <button onClick={handleClearScrollPosition}>Clear Scroll Position</button>
1362
+ * </div>
1363
+ * );
1364
+ * }
1365
+ *
1366
+ * export default ScrollableComponent;
1367
+ * @endexample
1368
+ */
176
1369
  export function useRestoreScrollPosition(key: string, ref: React.RefObject<HTMLElement>): void;
1370
+ /**
1371
+ *
1372
+ * A custom hook that provides access to set scroll positions.
1373
+ *
1374
+ * @example
1375
+ *
1376
+ * import { useSetScrollPosition } from "@bigbinary/neeto-commons-frontend/react-utils/useRestoreScrollPosition
1377
+ *
1378
+ * const setScrollPosition = useSetScrollPosition();
1379
+ * setScrollPosition("myKey", 100);
1380
+ * @endexample
1381
+ */
177
1382
  export function useSetScrollPosition(): (key: string, value: number) => void;
1383
+ /**
1384
+ *
1385
+ * A custom hook that retrieves the scroll position for a given key.
1386
+ *
1387
+ * @example
1388
+ *
1389
+ * import { useGetScrollPosition } from "@bigbinary/neeto-commons-frontend/react-utils/useRestoreScrollPosition
1390
+ *
1391
+ * const getScrollPosition = useGetScrollPosition();
1392
+ * const position = getScrollPosition("myKey");
1393
+ * @endexample
1394
+ */
178
1395
  export function useGetScrollPosition(): (key: string) => number | undefined;
179
- export function useRemoveScrollPosition():(key: string) => void;
180
-
1396
+ /**
1397
+ *
1398
+ * A custom hook that removes a scroll position entry for a specified key.
1399
+ *
1400
+ * @example
1401
+ *
1402
+ * import { useRemoveScrollPosition } from "@bigbinary/neeto-commons-frontend/react-utils/useRestoreScrollPosition
1403
+ *
1404
+ * const removeScrollPosition = useRemoveScrollPosition();
1405
+ * removeScrollPosition("myKey");
1406
+ * @endexample
1407
+ */
1408
+ export function useRemoveScrollPosition(): (key: string) => void;
1409
+ /**
1410
+ *
1411
+ * The useFuncDebounce hook is a utility that extends the benefits of debouncing
1412
+ *
1413
+ * to functions.
1414
+ *
1415
+ * When the debounced function is called, it sets a timer to execute the original
1416
+ *
1417
+ * function after a specified delay. If the debounced function is called again
1418
+ *
1419
+ * before the timer expires, the previous timer is cleared. This effectively delays
1420
+ *
1421
+ * the execution of the original function until the debounced function hasn't been
1422
+ *
1423
+ * called for the specified delay period.
1424
+ *
1425
+ * The hook also provides a cancel method to manually cancel the execution of the
1426
+ *
1427
+ * debounced function before it triggers.
1428
+ *
1429
+ * The following code snippet demonstrates the usage of useFuncDebounce in the
1430
+ *
1431
+ * delaying the invocation of the fetch method until the user pauses typing for a
1432
+ *
1433
+ * specific period.
1434
+ *
1435
+ * @example
1436
+ *
1437
+ * import { useFuncDebounce } from "@bigbinary/neeto-commons-frontend/react-utils";
1438
+ *
1439
+ * const searchForProducts = useFuncDebounce(async key => {
1440
+ * // this function will be triggered once after user stops typing for 300ms
1441
+ * const products = await productsApi.fetch(key);
1442
+ * // do something with the products
1443
+ * }, 300);
1444
+ *
1445
+ * // component
1446
+ * <Input onChange={e => searchForProducts(e.target.value)} />;
1447
+ * <Button onClick={() => searchForProducts.cancel()}>Cancel search</Button>;
1448
+ * @endexample
1449
+ */
181
1450
  export const useFuncDebounce: {
182
1451
  <F extends Function>(func: F, delay?: number): F;
183
1452
  cancel: () => void;
184
1453
  };
185
-
1454
+ /**
1455
+ *
1456
+ * usePersistedQuery is an wrapper function around
1457
+ *
1458
+ * useQuery hook
1459
+ *
1460
+ * from react-query. In addition to all the functionalities offered useQuery,
1461
+ *
1462
+ * this hook also stores the received response in localStorage. For subsequent
1463
+ *
1464
+ * page loads, the hook will be serving data from localStorage until the API
1465
+ *
1466
+ * response is received.
1467
+ *
1468
+ * usePersistedQuery will use the staleTime config from options parameter (if
1469
+ *
1470
+ * present) to determine the expiry of the localStorage cache. The hook will not
1471
+ *
1472
+ * return data from localStorage if it is expired. Instead it will wait for the
1473
+ *
1474
+ * API response to become available.
1475
+ *
1476
+ * You can use isFreshLoading property from the return value of the hook to know
1477
+ *
1478
+ * whether the hook is waiting for the API. data won't be available (will be
1479
+ *
1480
+ * undefined) until isFreshLoading turns to false.
1481
+ *
1482
+ * It also provides a method getCache to get the cached data from localStorage
1483
+ *
1484
+ * by providing the queryKey.
1485
+ *
1486
+ * The following code snippet demonstrates the usage of usePersistedQuery in
1487
+ *
1488
+ * caching API responses and serving cached data while waiting for fresh data from
1489
+ *
1490
+ * the APIs.
1491
+ *
1492
+ * @example
1493
+ *
1494
+ * import { usePersistedQuery } from "@bigbinary/neeto-commons-frontend/react-utils";
1495
+ *
1496
+ * const useFetchUsers = options =>
1497
+ * usePersistedQuery(QUERY_KEYS.FETCH_USERS, usersApi.fetch, options);
1498
+ *
1499
+ * // Now we can use useFetchUsers as:
1500
+ * const { data, isLoading, isFreshLoading } = useFetchUsers();
1501
+ *
1502
+ * // To get the cached data from localStorage
1503
+ * const cachedUsersData = usePersistedQuery.getCache(QUERY_KEYS.FETCH_USERS);
1504
+ * @endexample
1505
+ */
186
1506
  export const usePersistedQuery: {
187
- <T>(
188
- queryKey: string | unknown[],
189
- fetch: () => Promise<T>,
190
- options?: UseQueryOptions
191
- ): UseQueryResult<T> & { isFreshLoading: boolean };
1507
+ <T>(queryKey: string | unknown[], fetch: () => Promise<T>, options?: UseQueryOptions): UseQueryResult<T> & {
1508
+ isFreshLoading: boolean;
1509
+ };
192
1510
  getCache: <T>(queryKey: string | unknown[]) => T | null;
193
1511
  };
194
-
195
- export function useFetchNeetoApps(
196
- options?: UseQueryOptions
197
- ): ReturnType<
198
- typeof usePersistedQuery<{
199
- neetoApps: { description: string; name: string; url: string }[];
200
- isOwner: boolean;
201
- }>
202
- >;
203
-
204
- export const withT: <
205
- Props extends { [key: string]: any },
206
- N extends Namespace = DefaultNamespace,
207
- TKPrefix extends KeyPrefix<N> = undefined
208
- >(
209
- Component: React.ComponentType<Props & { t: TFunction }>,
210
- options?: {
211
- withRef?: boolean;
212
- keyPrefix?: TKPrefix;
213
- },
214
- ns?: N
215
- ) => React.ComponentType<Props>;
216
-
1512
+ /**
1513
+ *
1514
+ * The useFetchNeetoApps hook calls
1515
+ *
1516
+ * neeto_apps_controller
1517
+ *
1518
+ * and fetches the response. neeto_apps_controller will return two information:
1519
+ *
1520
+ * This hook uses usePersistedQuery under the hood. So
1521
+ *
1522
+ * data will be immediately available except for the first page load. Additionally
1523
+ *
1524
+ * if the data is available in localStorage, it will be served from there until an
1525
+ *
1526
+ * explicit call to refetch is made.
1527
+ *
1528
+ * The following code snippet shows the usage of useFetchNeetoApps in fetching
1529
+ *
1530
+ * neetoApps and ownership status.
1531
+ *
1532
+ * @example
1533
+ *
1534
+ * import { useFetchNeetoApps } from "@bigbinary/neeto-commons-frontend/react-utils";
1535
+ *
1536
+ * const { neetoApps, isOwner } = useFetchNeetoApps();
1537
+ * @endexample
1538
+ */
1539
+ export function useFetchNeetoApps(options?: UseQueryOptions): ReturnType<typeof usePersistedQuery<{
1540
+ neetoApps: {
1541
+ description: string;
1542
+ name: string;
1543
+ url: string;
1544
+ }[];
1545
+ isOwner: boolean;
1546
+ }>>;
1547
+ /**
1548
+ *
1549
+ * withT is an HOC which provides the t function from react-i18next to the
1550
+ *
1551
+ * wrapped component as a prop. withT HOC should only be used in dumb components
1552
+ *
1553
+ * i.e, components which have no logic other than rendering something and the
1554
+ *
1555
+ * useTranslation hook.
1556
+ *
1557
+ * @example
1558
+ *
1559
+ * // Example usage of withT:
1560
+ * const ComponentWithTranslation = withT(({ t }) => <div>{t("some.key")}</div>);
1561
+ *
1562
+ * // Example usage of withT with forwarded ref:
1563
+ * const ComponentWithRef = withT(
1564
+ * React.forwardRef(({ t }, ref) => <div ref={ref}>{t("some.key")}</div>),
1565
+ * {
1566
+ * withRef: true,
1567
+ * }
1568
+ * );
1569
+ *
1570
+ * // Example usage of withT with keyPrefix:
1571
+ * const ComponentWithTranslation = withT(
1572
+ * ({ t }) => (
1573
+ * // t function will be called with the key "very.nested.key.some.key"
1574
+ * <div ref={ref}>{t("some.key")}</div>
1575
+ * ),
1576
+ * {
1577
+ * keyPrefix: "very.nested.key",
1578
+ * }
1579
+ * );
1580
+ * @endexample
1581
+ */
1582
+ export const withT: <Props extends {
1583
+ [key: string]: any;
1584
+ }, N extends Namespace = DefaultNamespace, TKPrefix extends KeyPrefix<N> = undefined>(Component: React.ComponentType<Props & {
1585
+ t: TFunction;
1586
+ }>, options?: {
1587
+ withRef?: boolean;
1588
+ keyPrefix?: TKPrefix;
1589
+ }, ns?: N) => React.ComponentType<Props>;
217
1590
  type QueryKeyOrFilters = QueryKey | QueryFilters;
218
-
219
- export function useMutationWithInvalidation<TData = unknown, TError = unknown, TVariables = void, TContext = unknown>(
220
- mutationFn: MutationFunction<TData, TVariables>,
221
- options: { keysToInvalidate: Array<QueryKeyOrFilters | ((data: TData, variables: TVariables, context: TContext | undefined) => QueryKeyOrFilters)> } & Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'>
222
- ): UseMutationResult<TData, TError, TVariables, TContext>;
223
-
1591
+ /**
1592
+ *
1593
+ * useMutationWithInvalidation is a wrapper function around the
1594
+ *
1595
+ * useMutation
1596
+ *
1597
+ * hook from react-query. It returns all the props from the useMutation hook and
1598
+ *
1599
+ * additionally, invalidates a list of query keys on mutation success.
1600
+ *
1601
+ * The following code snippet illustrates the usage of
1602
+ *
1603
+ * useMutationWithInvalidation across various scenarios.
1604
+ *
1605
+ * @example
1606
+ *
1607
+ * // useQuestionsApi
1608
+ * //Invalidate any query with query key starting with "QUESTIONS"
1609
+ * const useUpdateQuestions = () =>
1610
+ * useMutationWithInvalidation(questionsApi.update, {
1611
+ * keysToInvalidate: ["QUESTIONS"],
1612
+ * onSuccess: data => queryClient.setQueryData(["RESPONSES"], data),
1613
+ * });
1614
+ *
1615
+ * // The above is the same as writing
1616
+ * const useUpdateQuestions = options =>
1617
+ * useMutation(questionsApi.update, {
1618
+ * ...options,
1619
+ * onSuccess: (data, ...args) => {
1620
+ * queryClient.invalidateQueries({
1621
+ * queryKey: ["QUESTIONS"]
1622
+ * });
1623
+ * queryClient.setQueryData(["RESPONSES"], data);
1624
+ * options?.onSuccess(data, ...args);
1625
+ * },
1626
+ * });
1627
+ * @endexample
1628
+ * @example
1629
+ *
1630
+ * //Invalidate any query with query key starting with ["FORM", "QUESTIONS"]
1631
+ * const useUpdateQuestions = options =>
1632
+ * useMutationWithInvalidation(questionsApi.update, {
1633
+ * keysToInvalidate: [["FORM", "QUESTIONS"]],
1634
+ * ...options,
1635
+ * });
1636
+ *
1637
+ * // The above is the same as writing
1638
+ * const useUpdateQuestions = options =>
1639
+ * useMutation(questionsApi.update, {
1640
+ * ...options,
1641
+ * onSuccess: (...args) => {
1642
+ * queryClient.invalidateQueries({
1643
+ * queryKey: ["FORM", "QUESTIONS"],
1644
+ * });
1645
+ * options?.onSuccess(...args);
1646
+ * },
1647
+ * });
1648
+ * @endexample
1649
+ * @example
1650
+ *
1651
+ * //Invalidate any query with query key starting with "FORM" or starting with "QUESTIONS"
1652
+ * const useUpdateQuestions = options =>
1653
+ * useMutationWithInvalidation(questionsApi.update, {
1654
+ * keysToInvalidate: ["FORM", "QUESTIONS"],
1655
+ * ...options,
1656
+ * });
1657
+ *
1658
+ * // The above is the same as writing
1659
+ * const useUpdateQuestions = options =>
1660
+ * useMutation(questionsApi.update, {
1661
+ * ...options,
1662
+ * onSuccess: () => {
1663
+ * queryClient.invalidateQueries({
1664
+ * queryKey: ["FORM"],
1665
+ * });
1666
+ * queryClient.invalidateQueries({
1667
+ * queryKey: ["QUESTIONS"],
1668
+ * });
1669
+ * options?.onSuccess(...args);
1670
+ * },
1671
+ * });
1672
+ * @endexample
1673
+ * @example
1674
+ *
1675
+ * //Invalidate any query with query key starting with ["QUESTION", id]
1676
+ * const useUpdateQuestions = options =>
1677
+ * useMutationWithInvalidation(questionsApi.update, {
1678
+ * keysToInvalidate: [(_, { id }) => ["QUESTION", id]],
1679
+ * ...options,
1680
+ * });
1681
+ *
1682
+ * // The above is the same as writing
1683
+ * const useUpdateQuestions = options =>
1684
+ * useMutation(questionsApi.update, {
1685
+ * ...options,
1686
+ * onSuccess: (...args) => {
1687
+ * const [_, { id }] = args;
1688
+ * queryClient.invalidateQueries({
1689
+ * queryKey: ["QUESTION", id],
1690
+ * });
1691
+ * options?.onSuccess(...args);
1692
+ * },
1693
+ * });
1694
+ *
1695
+ * // Update question component
1696
+ * const { mutate: updateQuestions, isPending } = useUpdateQuestions({
1697
+ * onError: e => logger.error(e),
1698
+ * });
1699
+ * @endexample
1700
+ */
1701
+ export function useMutationWithInvalidation<TData = unknown, TError = unknown, TVariables = void, TContext = unknown>(mutationFn: MutationFunction<TData, TVariables>, options: {
1702
+ keysToInvalidate: Array<QueryKeyOrFilters | ((data: TData, variables: TVariables, context: TContext | undefined) => QueryKeyOrFilters)>;
1703
+ } & Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'>): UseMutationResult<TData, TError, TVariables, TContext>;
1704
+ /**
1705
+ *
1706
+ * The useQueryParams hook can be used to retrieve the query parameters whenever
1707
+ *
1708
+ * the location changes. A change in location will trigger rerender when using this
1709
+ *
1710
+ * hook.
1711
+ *
1712
+ * This hook will return an object containing all the query parameters in camel
1713
+ *
1714
+ * case. It will return an empty object if no query parameters are present.
1715
+ *
1716
+ * You can set toCamelCase to false if you don't want to apply any transformation to the keys.
1717
+ *
1718
+ * More details on working:
1719
+ *
1720
+ * https://www.loom.com/share/4f369cff56e845428d5ef7451759469c
1721
+ *
1722
+ * @example
1723
+ *
1724
+ * const queryParams = useQueryParams();
1725
+ * // output: { sort_by: "description", order_by: "desc" }
1726
+ * const { sortBy, orderBy } = useQueryParams();
1727
+ *
1728
+ * const { sort_by, order_by } = useQueryParams({ toCamelCase: false });
1729
+ * @endexample
1730
+ */
224
1731
  export function useQueryParams(options?: qsOptionsType): QueryParamsType;
225
-
226
1732
  type BreakpointKeys = 'mobile' | 'tablet' | 'desktop' | 'largeDesktop';
227
-
228
- type Breakpoints = {
229
- [key in BreakpointKeys]: boolean;
230
- }
231
-
232
- export function useBreakpoints<T extends {}>(breakpointOverrides?: (window: Window) => Partial<T & Breakpoints>): { currentSize: BreakpointKeys | keyof T; isSize: (size: BreakpointKeys | keyof T) => boolean };
1733
+ type Breakpoints = { [key in BreakpointKeys]: boolean };
1734
+ /**
1735
+ *
1736
+ * The useBreakpoints hook is a utility for responsive styling on components
1737
+ *
1738
+ * based on the viewport size. It returns the current breakpoint name and a
1739
+ *
1740
+ * function to check if the current breakpoint matches a given breakpoint name. It
1741
+ *
1742
+ * also re-renders the component when the current breakpoint changes.
1743
+ *
1744
+ * Note: Use this hook only if you need the component to re-render when the
1745
+ *
1746
+ * current breakpoint change happens. If all you need is plain read and write
1747
+ *
1748
+ * operations on the current breakpoint, prefer the vanilla window.matchMedia or
1749
+ *
1750
+ * window.innerWidth API.
1751
+ *
1752
+ * @example
1753
+ *
1754
+ * (window) => {
1755
+ * mobile: window.innerWidth < 768,
1756
+ * tablet: window.innerWidth >= 768 && window.innerWidth < 1024,
1757
+ * desktop: window.innerWidth >= 1024 && window.innerWidth < 1280,
1758
+ * largeDesktop: window.innerWidth >= 1280,
1759
+ * }
1760
+ * @endexample
1761
+ * This hook will return an object with two values currentSize and isSize.
1762
+ *
1763
+ * The following code snippet illustrates the usage of useLocalStorage in
1764
+ *
1765
+ * implementing a theme-switching feature.
1766
+ *
1767
+ * @example
1768
+ *
1769
+ * import { useBreakpoints } from "@bigbinary/neeto-commons-frontend/react-utils";
1770
+ *
1771
+ * const { currentSize, isSize } = useBreakpoints();
1772
+ *
1773
+ * // When window.innerWidth is 1028
1774
+ * console.log(currentSize); // logs `tablet`
1775
+ * console.log(isSize("mobile")); // logs `false`
1776
+ * console.log(isSize("tablet")); // logs `true`
1777
+ * @endexample
1778
+ * We can also override the default breakpoints by passing a function to the
1779
+ *
1780
+ * useBreakpoints hook.
1781
+ *
1782
+ * @example
1783
+ *
1784
+ * import { useBreakpoints } from "@bigbinary/neeto-commons-frontend/react-utils";
1785
+ *
1786
+ * // Overriding the default breakpoints
1787
+ * const { currentSize, isSize } = useBreakpoints(window => ({
1788
+ * largeDesktop: window.innerWidth >= 1280 && window.innerWidth < 1440,
1789
+ * extraLargeDesktop: window.innerWidth >= 1440,
1790
+ * }));
1791
+ *
1792
+ * // When window.innerWidth is 1440
1793
+ * console.log(currentSize); // logs `extraLargeDesktop`
1794
+ * console.log(isSize("extraLargeDesktop")); // logs `true`
1795
+ * @endexample
1796
+ */
1797
+ export function useBreakpoints<T extends {}>(breakpointOverrides?: (window: Window) => Partial<T & Breakpoints>): {
1798
+ currentSize: BreakpointKeys | keyof T;
1799
+ isSize: (size: BreakpointKeys | keyof T) => boolean;
1800
+ };