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