@bigbinary/neeto-commons-frontend 2.0.65 → 2.0.66

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 (2) hide show
  1. package/package.json +1 -1
  2. package/react-utils.d.ts +419 -154
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigbinary/neeto-commons-frontend",
3
- "version": "2.0.65",
3
+ "version": "2.0.66",
4
4
  "description": "A package encapsulating common code across neeto projects including initializers, utility functions, common components and hooks and so on.",
5
5
  "repository": "git@github.com:bigbinary/neeto-commons-frontend.git",
6
6
  "author": "Amaljith K <amaljith.k@bigbinary.com>",
package/react-utils.d.ts CHANGED
@@ -1,139 +1,309 @@
1
- import dayjs from "dayjs";
2
1
  import React from "react";
3
- export function resetAuthTokens(): void;
2
+ import { RouteProps } from "react-router-dom";
3
+ import { Notice } from "@honeybadger-io/js/dist/server/types/core/types";
4
+ import { History } from "history";
5
+ import { StoreApi, UseBoundStore } from "zustand";
4
6
  /**
5
7
  *
6
- * Curried: true
8
+ * ErrorBoundary which reports frontend errors to HoneyBadger
7
9
  *
8
- * It is a curried function that accepts a function as the first parameter and an
10
+ * This component will wrap its children with the error boundary provided by
9
11
  *
10
- * event as the second, and executes the given function with event.target.value
12
+ * @honeybadger-io/react package. In this component, we will create a honeybadger
11
13
  *
12
- * Usage:
14
+ * configuration object using the API key, environment and project version which we
15
+ *
16
+ * obtained from the globalProps and pass the created object to error boundary
17
+ *
18
+ * provided by honeybadger. We are also filtering the false-positive errors using
19
+ *
20
+ * beforeNotify method.
21
+ *
22
+ * For global error handling, we need to wrap the Main component with this
23
+ *
24
+ * HoneybadgerErrorBoundary component as shown below.
13
25
  *
14
26
  * @example
15
27
  *
16
- * const onChange = val => console.log(`Value = ${val}`);
17
- *
18
- * <input onChange={withEventTargetValue(onChange)} />;
19
- *
20
- * // For example, in this case when user types "1" in the input field, "Value = 1" will be printed in the console.
28
+ * <HoneybadgerErrorBoundary
29
+ * ErrorComponent={ErrorComponent}
30
+ * filterErrors={notice => !/IgnorableError/.test(notice.message)}
31
+ * >
32
+ * <Main />
33
+ * </HoneybadgerErrorBoundary>
21
34
  * @endexample
35
+ * ErrorComponent is the component which will be rendered when an error is thrown
36
+ *
37
+ * during rendering. This is an optional prop and if this prop is not provided then
38
+ *
39
+ * honeybadger will use DefaultErrorComponent for fallback UI.
40
+ *
41
+ * filterErrors is a function which takes the honeybadger notice as argument and
42
+ *
43
+ * returns a boolean. It should return true if the error is to be reported and
44
+ *
45
+ * false if not.
46
+ *
22
47
  */
23
- export function withEventTargetValue(func: (value: string) => void, event: React.ChangeEventHandler<HTMLInputElement>): void;
48
+ export const HoneybadgerErrorBoundary: React.FC<{
49
+ ErrorComponent?: React.ReactNode | React.ComponentType<any>;
50
+ filterErrors?: (error: Notice) => boolean;
51
+ }>;
24
52
  /**
25
53
  *
26
- * Curried: true
54
+ * A route that will restrict access to it based on a specified condition.
27
55
  *
28
- * It is a curried function that accepts a function as the first parameter and an
56
+ * If the given condition is true, it acts identical to a normal route. Otherwise
29
57
  *
30
- * event as the second, and executes the given function with event.target.value
58
+ * we have two options: it can either redirect user to a different path or it can
31
59
  *
32
- * Usage:
60
+ * render a supplied error page instead of the actual component in that route.
61
+ *
62
+ * If condition is not specified, it will assume the value of
63
+ *
64
+ * globalProps.authenticated by default.
65
+ *
66
+ * Here are some example use cases:
67
+ *
68
+ */
69
+ export function PrivateRoute(props: {
70
+ condition?: boolean;
71
+ redirectRoute?: string;
72
+ errorPage?: React.ReactNode;
73
+ } & RouteProps): JSX.Element;
74
+ type OptionsType = {
75
+ root?: Element | null;
76
+ rootMargin?: String;
77
+ threshold?: Number | Number[];
78
+ };
79
+ /**
80
+ *
81
+ * This hook allows you to detect when a target element intersects with an ancestor
82
+ *
83
+ * element. In simple words, it lets us know whether the target element is visible
84
+ *
85
+ * on the screen.
86
+ *
87
+ * This hook will accept two arguments an element and an options object. Passing an
88
+ *
89
+ * element using ref requires you to pass ref.current as an argument or pass an
90
+ *
91
+ * element that you accessed via getElementById/querySelector etc. Since it uses
92
+ *
93
+ * Intersection Observer API you can pass observer options such as root,
94
+ *
95
+ * rootMargin, threshold, etc as the second argument. You can read more about
96
+ *
97
+ * Intersection Observer API and the supported options from
98
+ *
99
+ * MDN Intersection Observer API.
33
100
  *
34
101
  * @example
35
102
  *
36
- * const onChange = val => console.log(`Value = ${val}`);
37
- *
38
- * <input onChange={withEventTargetValue(onChange)} />;
103
+ * const ref = useRef(null);
104
+ * const isHeadingWrapperVisible = useIsElementVisibleInDom(ref.current, {
105
+ * threshold: 0.5,
106
+ * });
39
107
  *
40
- * // For example, in this case when user types "1" in the input field, "Value = 1" will be printed in the console.
108
+ * return (
109
+ * <div>
110
+ * <div style={{ height: "100vh" }}>
111
+ * <h1>Scroll down to next section</h1>
112
+ * </div>
113
+ * <div ref={ref}>
114
+ * {isHeadingWrapperVisible && <h1>Hello I'm on the screen</h1>}
115
+ * </div>
116
+ * </div>
117
+ * );
41
118
  * @endexample
42
119
  */
43
- export function withEventTargetValue(func: (value: string) => void): (event: React.ChangeEventHandler<HTMLInputElement>) => void;
120
+ export function useIsElementVisibleInDom(target: Element | null, options?: OptionsType): Boolean;
44
121
  /**
45
122
  *
46
- * Curried: false
123
+ * Wrap this hook around a frequently updating state to get the previous value
47
124
  *
48
- * This function returns the subdomain of the current URL.
125
+ * until the updates are stopped. We can use this to limit the number of API calls
49
126
  *
50
- * Usage:
127
+ * triggered from a user input like search box.
128
+ *
129
+ * This hook accepts a value and a delay as an argument. The value returned by the
130
+ *
131
+ * hook will only reflect the latest value when the hook has not been called for
132
+ *
133
+ * the specified time period delay.
51
134
  *
52
135
  * @example
53
136
  *
54
- * // Let the current url be "https://spinkart.example.com".
55
- * getSubdomain();
137
+ * const [searchKey, setSearchKey] = useState("");
138
+ * const debouncedSearchKey = useDebounce(searchKey, 300);
56
139
  *
57
- * // output: spinkart
140
+ * useEffect(() => {
141
+ * // will be triggered with the latest value of input
142
+ * // only after 300ms after the user stops typing
143
+ * }, [debouncedSearchKey]);
144
+ *
145
+ * // component
146
+ * <Input onChange={e => setSearchKey(e.target.value)} />;
58
147
  * @endexample
59
148
  */
60
- export function getSubdomain(): string;
149
+ export function useDebounce<T>(value: T, delay?: number): T;
61
150
  /**
62
151
  *
63
- * Curried: false
64
- *
65
- * Returns the specified hardcoded data after some delay for simulating an API
152
+ * Similar to useDebounce but this hook accepts a function as an argument. That
66
153
  *
67
- * call.
154
+ * function will be executed only when the dependencies stops changing for a while.
68
155
  *
69
- * This function will simulate an API call and retrieve the hardcoded success/error
156
+ * This hook accepts a function as an argument. It will return a debounced version
70
157
  *
71
- * responses after some delay based on the given error probability. This function
158
+ * of that function. The debounced function comes with a cancel method which can
72
159
  *
73
- * is helpful when we are building the frontend before the backend is ready.
160
+ * be used to cancel the delayed function invocation.
74
161
  *
75
162
  * @example
76
163
  *
77
- * simulateApiCall(hardCodedResponseData, hardCodedErrorResponse);
164
+ * const searchForProducts = useFuncDebounce(async key => {
165
+ * // this function will be triggered once after user stops typing for 300ms
166
+ * const products = await productsApi.fetch(key);
167
+ * // do something with the products
168
+ * }, 300);
169
+ *
170
+ * // component
171
+ * <Input onChange={e => searchForProducts(e.target.value)} />;
172
+ * <Button onClick={() => searchForProducts.cancel()}>Cancel search</Button>;
78
173
  * @endexample
79
174
  */
80
- export function simulateApiCall<T>(result: T, error?: any, errorProbability?: number, delayMs?: number): Promise<T>;
175
+ export function useFuncDebounce<F extends Function>(func: F, delay?: number): F & {
176
+ cancel: () => void;
177
+ };
81
178
  /**
82
179
  *
83
- * Curried: false
180
+ * This hook can be used to sync state to local storage so that it persists through
84
181
  *
85
- * Copies the given string to clipboard and shows a success toaster message.
182
+ * a page refresh.
86
183
  *
87
- * This function accepts a string as an argument and copies it to the clipboard.
184
+ * Note: use this hook only if you need the component to re-render while
88
185
  *
89
- * Also, it accepts two optional arguments: a boolean flag to indicate whether a
186
+ * updating the local storage value. If all you need is plain read and write
90
187
  *
91
- * toaster should be shown and a message to be shown in the toaster. By default the
188
+ * operations on the localStorage, prefer the vanilla localStorage API functions.
92
189
  *
93
- * show toaster flag is set to true and the toaster message is set to "Copied to
190
+ * This hook is very similar to useState. The only difference is that you must
94
191
  *
95
- * clipboard!". You can override these defaults by passing the appropriate values
192
+ * pass the storage key in the 1st parameter so that we can default to that value
96
193
  *
97
- * to the function.
194
+ * on page load instead of specified initial value.
98
195
  *
99
196
  * @example
100
197
  *
101
- * copyToClipboard("https://spinkart.example.com", {
102
- * showToastr: true,
103
- * message: "URL copied successfully!",
104
- * });
198
+ * // here "theme" is the storage key and "light" is the initial value
199
+ * const [theme, setTheme] = useLocalStorage("theme", "light");
105
200
  *
106
- * // If the URL is copied to the clipboard, a toaster message will be shown with the message "URL copied successfully!"
201
+ * return (
202
+ * <Select
203
+ * options={[
204
+ * { label: "light", value: "light" },
205
+ * { label: "dark", value: "dark" },
206
+ * ]}
207
+ * // when we change the theme, the same will be stored in local storage with the key "theme"
208
+ * onChange={option => setTheme(option.value)}
209
+ * />
210
+ * );
107
211
  * @endexample
212
+ * To remove the value from local storage we can call the setter method with null
213
+ *
214
+ * or undefined.
215
+ *
108
216
  */
109
- export function copyToClipboard(text: string, configs?: {
110
- showToastr?: boolean;
111
- message?: string;
112
- }): void;
217
+ export function useLocalStorage<T>(key: string, initialValue?: T): [T, (value: T) => void];
113
218
  /**
114
219
  *
115
- * Curried: false
220
+ * A hook used to detect clicks outside of a specified element.
116
221
  *
117
- * Builds a URL by inflating route like template string (example:
222
+ * This hook will accept two arguments: a ref and a handler. The ref is a reference
118
223
  *
119
- * /products/:productId/variants/:id) using the given params. Any extra
224
+ * to the element for which we want to detect outside clicks and handler is the
120
225
  *
121
- * properties in the params will be attached as query parameters to the URL.
226
+ * action we want to perform when we click outside the element.
122
227
  *
123
228
  * @example
124
229
  *
125
- * buildUrl("/products/:id", { id: "123" }); // output "/products/123"
126
- * buildUrl("/products", { search: "abc" }); // output "/products?search=abc"
127
- * buildUrl("/products/:productId/variants/:variantId/attributes", {
128
- * productId: "123",
129
- * variantId: "456",
130
- * search: "abc",
131
- * page: 1,
132
- * per_page: 10,
133
- * }); // output "/products/123/variants/456/attributes?page=1&per_page=10&search=abc"
230
+ * const ref = useRef();
231
+ * const [isModalOpen, setIsModalOpen] = useState(false);
232
+ *
233
+ * useOnClickOutside(ref, () => setIsModalOpen(false));
234
+ *
235
+ * return (
236
+ * <>
237
+ * { When we click inside of this modal, it won't close. But when we click outside, it'll close! }
238
+ * {isModalOpen && (
239
+ * <div ref={ref}>
240
+ * <p>Hello from Modal!</p>
241
+ * </div>
242
+ * )}
243
+ * <button onClick={() => setIsModalOpen(true)}>Open Modal</button>
244
+ * </>
245
+ * );
134
246
  * @endexample
135
247
  */
136
- export function buildUrl(route: string, params: object): string;
248
+ export function useOnClickOutside<T>(ref: React.MutableRefObject<T>, handler: (event: MouseEvent | TouchEvent) => any);
249
+ /**
250
+ *
251
+ * A hook that returns the previous value of a variable before the last update.
252
+ *
253
+ * In the below example, when count is updated to 10, previousCount will be 0.
254
+ *
255
+ * If count is again updated to 20, previousCount will be 10.
256
+ *
257
+ * @example
258
+ *
259
+ * const [count, setCount] = useState(0);
260
+ * const previousCount = usePrevious(count);
261
+ * @endexample
262
+ */
263
+ export function usePrevious<T>(value: T): T;
264
+ /**
265
+ *
266
+ * A hook very similar to useEffect. The only difference is that it will not
267
+ *
268
+ * execute the callback in the initial mount. The callback will be triggered only
269
+ *
270
+ * if the dependencies change.
271
+ *
272
+ */
273
+ export function useUpdateEffect(effect: () => void, deps: any[]): void;
274
+ /**
275
+ *
276
+ * This hook will return true if any API request fails with 404 or 403 status.
277
+ *
278
+ * Until any such API response is received, it will return false. It can be used
279
+ *
280
+ * to render ErrorPage conditionally. Refer:
281
+ *
282
+ * axios error response handler
283
+ *
284
+ * for more details.
285
+ *
286
+ */
287
+ export function useDisplayErrorPage(): boolean;
288
+ /**
289
+ *
290
+ * A zustand store containing the status code of the latest API failed with 403 or
291
+ *
292
+ * 404 status (statusCode) and a boolean flag (showErrorPage) stating whether
293
+ *
294
+ * the error page should be rendered or not.
295
+ *
296
+ * This store is automatically managed by neeto-commons-frontend using its axios
297
+ *
298
+ * interceptors. You can also use this store if you need to display an error page
299
+ *
300
+ * from your frontend logic.
301
+ *
302
+ */
303
+ export const useErrorDisplayStore: UseBoundStore<StoreApi<{
304
+ showErrorPage: boolean;
305
+ statusCode: number;
306
+ }>>;
137
307
  type TimerType = {
138
308
  lastUpdated: number;
139
309
  interval: number;
@@ -176,168 +346,263 @@ type TimerType = {
176
346
  * @endexample
177
347
  */
178
348
  export function useTimer(interval: number): TimerType;
179
- type DateTimeType = string | number | dayjs.Dayjs | Date | null | undefined;
180
- export const timeFormat: {
181
- fromNow: (time: DateTimeType) => string;
182
- time: (time: DateTimeType) => string;
183
- date: (time: DateTimeType) => string;
184
- dateWeek: (time: DateTimeType) => string;
185
- dateWeekWithoutYear: (time: DateTimeType) => string;
186
- dateTime: (time: DateTimeType) => string;
187
- dateWeekTime: (time: DateTimeType) => string;
188
- extended: (time: DateTimeType) => string;
189
- };
190
- export const dateFormat: typeof timeFormat;
349
+ type ZustandConfigType = (set: (data: any) => void, get: () => any, api: any) => any;
191
350
  /**
192
351
  *
193
- * Curried: false
352
+ * A zustand middleware function that prevents the actions from getting
353
+ *
354
+ * overwritten.
355
+ *
356
+ * Usage:
357
+ *
358
+ * @example
359
+ *
360
+ * const useStore = create(
361
+ * withImmutableActions(set => ({
362
+ * value: 10,
363
+ * // other properties ...
364
+ * setValue: ({ value }) => set({ value }),
365
+ * setGlobalState: set,
366
+ * // other actions ...
367
+ * }))
368
+ * );
369
+ * @endexample
370
+ * In the above example, usages like this will throw an error, because, actions
371
+ *
372
+ * should not be overwritten:
194
373
  *
195
- * Converts the given number to a locale string (converts to a comma separated
374
+ * @example
196
375
  *
197
- * string). It automatically identifies the locale using globalProps. If a valid
376
+ * setGlobalState({ value: 0, setValue: () => {} });
377
+ * @endexample
378
+ * Actions can be assigned its own value. This is to ensure that curried ramda
198
379
  *
199
- * value isn't present in globalProps, it will rely on the current browser's
380
+ * functions can be used in conjunction with zustand action. For example, this
200
381
  *
201
- * locale.
382
+ * usage will not throw any error:
202
383
  *
203
- * The function also accepts options, which will be forwarded to
384
+ * @example
204
385
  *
205
- * Number.prototype.toLocaleString, which can be used for additional
386
+ * setGlobalState(state => ({ value: 0, setValue: state.setValue }));
387
+ * @endexample
388
+ * The 2nd parameter to overwrite the entire state will be ignored. Both of the
206
389
  *
207
- * configurations like rounding, currency, units etc.
390
+ * following lines of code work identical to each other:
208
391
  *
209
392
  * @example
210
393
  *
211
- * toLocale(1000000); // "1,000,000" when locale is "en-US"
212
- * toLocale(1000000); // "10,00,000" when locale is "en-IN"
213
- * toLocale(1000000.987, { maximumFractionDigits: 2 }); // "1,000,000.99"
214
- * toLocale(1000000.987, {
215
- * currencyDisplay: "narrowSymbol",
216
- * style: "currency",
217
- * currency: "INR",
218
- * }); // "₹1,000,000.99"
394
+ * setGlobalState(state => ({ value: 0 }), true);
395
+ * setGlobalState(state => ({ value: 0 }));
219
396
  * @endexample
220
397
  */
221
- export function toLocale(number: string | number, options?: Intl.NumberFormatOptions): string;
222
- type qsOptionsType = {
223
- comma?: boolean | undefined;
224
- delimiter?: string | RegExp | undefined;
225
- depth?: number | false | undefined;
226
- decoder?: ((str: string, defaultDecoder: any, charset: string, type: "key" | "value") => any) | undefined;
227
- arrayLimit?: number | undefined;
228
- parseArrays?: boolean | undefined;
229
- allowDots?: boolean | undefined;
230
- plainObjects?: boolean | undefined;
231
- allowPrototypes?: boolean | undefined;
232
- parameterLimit?: number | undefined;
233
- strictNullHandling?: boolean | undefined;
234
- ignoreQueryPrefix?: boolean | undefined;
235
- charset?: "utf-8" | "iso-8859-1" | undefined;
236
- charsetSentinel?: boolean | undefined;
237
- interpretNumericEntities?: boolean | undefined;
398
+ export function withImmutableActions(config: ZustandConfigType): ZustandConfigType;
399
+ export declare type ZustandStoreHook = {
400
+ (selector: (state: any) => any, comparator?: (a: any, b: any) => boolean): any;
401
+ (): any;
238
402
  };
239
- type QueryParamsType = {
240
- [key: string]: any;
403
+ /**
404
+ *
405
+ * This hook calls onSubmit callback when Enter (aka Return) key is pressed. It
406
+ *
407
+ * will not submit when Shift + Enter is pressed. Shift + Enter can be used to
408
+ *
409
+ * add new lines to text area in the form.
410
+ *
411
+ * The hook accepts a callback, onSubmit, which will be called with no arguments
412
+ *
413
+ * when Enter key press is detected.
414
+ *
415
+ * The hook returns a ref. This need to be attached to the input element to be
416
+ *
417
+ * listened to.
418
+ *
419
+ * @example
420
+ *
421
+ * const inputRef = useFieldSubmit(() => {
422
+ * const inputValue = inputRef.current.value;
423
+ * console.log(inputValue);
424
+ * });
425
+ *
426
+ * return <textarea ref={inputRef} />;
427
+ * @endexample
428
+ */
429
+ export function useFieldSubmit(onSubmit: () => any): {
430
+ current: HTMLInputElement & HTMLTextAreaElement;
241
431
  };
242
432
  /**
243
433
  *
244
- * Curried: false
434
+ * An HOC which sets the browser title with the given value when the wrapped
245
435
  *
246
- * This function returns all the query parameters of the current URL as an object.
436
+ * component is rendered. If title is not explicitly provided, it will render
247
437
  *
248
- * Usage:
438
+ * globalProps.appName as the page title.
249
439
  *
250
440
  * @example
251
441
  *
252
- * // Let the current url be "https://example.com?search=something&sort=date".
253
- * getQueryParams();
442
+ * // assume this code in neetoStore
443
+ * const ProductsPage = props => <>Your page content here</>;
444
+ * export default withTitle(ProductsPage, "All products");
445
+ * // will set the browser title to `All products | neetoStore` when this page is rendered.
446
+ * @endexample
447
+ */
448
+ export function withTitle(Component: () => JSX.Element, title?: string): (props) => JSX.Element;
449
+ /**
450
+ *
451
+ * A browser push notifications utility function which asks the user permissions to send notifications and then register the browser with the notification service.
452
+ *
453
+ * After the user logs in, we need to ask the user permissions to send notifications and then register the browser with the notification service.
454
+ *
455
+ * You can use the registerBrowserNotifications utility function to do this. It can be called on any event after login based on the application's logic and requirement.
456
+ *
457
+ * Here as an example, we are calling registerBrowserNotifications method inside the Login component after the Authentication API request. This helps to associate the browser for that particular user.
458
+ *
459
+ * @example
460
+ *
461
+ * import { registerBrowserNotifications } from "neetocommons/react-utils";
254
462
  *
255
- * // output: { search: "something", sort: "date" }
463
+ * const handleLogin = async () => {
464
+ * try {
465
+ * // Authentication API request
466
+ * await registerBrowserNotifications();
467
+ * history.push(DASHBOARD_URL);
468
+ * } catch {}
469
+ * };
256
470
  * @endexample
471
+ * The above mentioned feature is currently supported for chromium-based browsers.
472
+ *
473
+ * Safari (iOS) is currently WIP.
474
+ *
475
+ * Any other browser which is not mentioned in above will be considered as
476
+ *
477
+ * unsupported.
478
+ *
257
479
  */
258
- export function getQueryParams(options?: qsOptionsType): QueryParamsType;
480
+ export async function registerBrowserNotifications(): Promise<void>;
259
481
  /**
260
482
  *
261
- * Curried: false
483
+ * A browser push notifications utility function which destroys the browser subscriptions from the user's devices. This helps in unsubscribing from browser push notifications.
262
484
  *
263
- * This function joins the given strings with hyphen.
485
+ * When the browser subscriptions expires for the user's devices or when the user decides to logout,then destroy the generated browser subscription for the user.
264
486
  *
265
- * Usage:
487
+ * You can use the destroyBrowserSubscription utility function to do this. It can be called on any event before logout based on the application's logic and requirement.
488
+ *
489
+ * Here as an example:
490
+ *
491
+ * In the Logout component, we are calling destroyBrowserSubscription method before the Logout API request. This helps to destroy the browser subscription from the user's devices.
266
492
  *
267
493
  * @example
268
494
  *
269
- * joinHyphenCase("hello", "world"); // output: "hello-world"
495
+ * import {destroyBrowserSubscription } from "neetocommons/react-utils";
496
+ *
497
+ * const handleLogout = async () => {
498
+ * try {
499
+ * await destroyBrowserSubscription(); //Before logout request
500
+ * // Logout API request
501
+ * window.location.href = LOGIN_PATH;
502
+ * } catch {}
503
+ * };
270
504
  * @endexample
505
+ * The above mentioned feature is currently supported for chromium-based browsers.
506
+ *
507
+ * Safari (iOS) is currently WIP.
508
+ *
509
+ * Any other browser which is not mentioned in above will be considered as
510
+ *
511
+ * unsupported.
512
+ *
271
513
  */
272
- export function joinHyphenCase(...args: string[]): string;
514
+ export async function destroyBrowserSubscription(): Promise<void>;
273
515
  /**
274
516
  *
275
- * Curried: false
517
+ * Curried: true
518
+ *
519
+ * This function can be used to handle onClick actions that redirects to a URL. It opens up the URL in a new tab if ctrl/cmd + click event is recieved. Otherwise, simply redirects to the provided URL in the same tab. URL can be passed as string or a history location object can be passed instead.
520
+ *
521
+ * Usage:
276
522
  *
277
- * Creates a debounced function that will execute the given function after the
523
+ * @example
278
524
  *
279
- * stated wait time in milliseconds has elapsed since the last time it was invoked.
525
+ * handleMetaClick(history, "/dashboard", e); //Opens "/dashboard" in a new tab if metaKey/CtrlKey is pressed. Otherwise simply redirects to "/dashboard".
526
+ * handleMetaClick(history, {pathname: "/dashboard", state: "abc"}, e); //Opens "/dashboard" in a new tab if metaKey/CtrlKey is pressed. Otherwise, redirects to "/dashboard" by preserving the state.
527
+ *
528
+ * @endexample
529
+ */
530
+ export function handleMetaClick(history: History, params: string | object, event: React.MouseEvent<HTMLElement, MouseEvent>): void;
531
+ /**
280
532
  *
281
- * It accepts the function to be debounced as the first argument, the delay in
533
+ * Curried: true
282
534
  *
283
- * milliseconds as the second argument.
535
+ * This function can be used to handle onClick actions that redirects to a URL. It opens up the URL in a new tab if ctrl/cmd + click event is recieved. Otherwise, simply redirects to the provided URL in the same tab. URL can be passed as string or a history location object can be passed instead.
284
536
  *
285
537
  * Usage:
286
538
  *
287
539
  * @example
288
540
  *
289
- * const searchForProducts = debounce(async key => {
290
- * // this function will be triggered once after user stops typing for 300ms
291
- * const products = await productsApi.fetch(key);
292
- * // do something with the products
293
- * }, 300);
294
- * <input onChange={e => searchForProducts(e.target.value)} />;
541
+ * handleMetaClick(history, "/dashboard", e); //Opens "/dashboard" in a new tab if metaKey/CtrlKey is pressed. Otherwise simply redirects to "/dashboard".
542
+ * handleMetaClick(history, {pathname: "/dashboard", state: "abc"}, e); //Opens "/dashboard" in a new tab if metaKey/CtrlKey is pressed. Otherwise, redirects to "/dashboard" by preserving the state.
543
+ *
295
544
  * @endexample
296
545
  */
297
- export function debounce<F extends Function>(func: F, delay?: number): F;
546
+ export function handleMetaClick(history: History, params: string | object): (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
298
547
  /**
299
548
  *
300
- * Curried: false
549
+ * Curried: true
301
550
  *
302
- * This function will return true if the current user has the given permission.
551
+ * This function can be used to handle onClick actions that redirects to a URL. It opens up the URL in a new tab if ctrl/cmd + click event is recieved. Otherwise, simply redirects to the provided URL in the same tab. URL can be passed as string or a history location object can be passed instead.
303
552
  *
304
553
  * Usage:
305
554
  *
306
555
  * @example
307
556
  *
308
- * hasPermission("user.view_settings");
557
+ * handleMetaClick(history, "/dashboard", e); //Opens "/dashboard" in a new tab if metaKey/CtrlKey is pressed. Otherwise simply redirects to "/dashboard".
558
+ * handleMetaClick(history, {pathname: "/dashboard", state: "abc"}, e); //Opens "/dashboard" in a new tab if metaKey/CtrlKey is pressed. Otherwise, redirects to "/dashboard" by preserving the state.
559
+ *
309
560
  * @endexample
310
561
  */
311
- export function hasPermission(permission: string): boolean;
562
+ export function handleMetaClick(history: History): (params: string | object, event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
312
563
  /**
313
564
  *
314
565
  * Curried: false
315
566
  *
316
- * This function will return true if the current user has any of the given
317
- *
318
- * permissions.
567
+ * This function can be used to check whether an onClick event has metaKey or ctrlKey pressed.
319
568
  *
320
569
  * Usage:
321
570
  *
322
571
  * @example
323
572
  *
324
- * hasAnyPermission("user.view_settings", "user.edit_settings");
573
+ * isMetaKeyPressed(event); //returns true if "event.metaKey || event.ctrlKey" is true, otherwise returns false.
574
+ *
325
575
  * @endexample
326
576
  */
327
- export function hasAnyPermission(...permissions: string[]): boolean;
577
+ export function isMetaKeyPressed(event: React.MouseEvent<HTMLElement, MouseEvent>): boolean;
578
+ type ConfigType = {
579
+ mode?: "default" | "global" | "scoped";
580
+ unbindOnUnmount?: boolean;
581
+ enabled?: boolean;
582
+ };
328
583
  /**
329
584
  *
330
- * Curried: false
585
+ * This is a configurable hook used for handling hotkeys in an application. We
331
586
  *
332
- * This function will return true if the current user has all of the given
587
+ * specify a hotkey and handler, whenever the hotkey is pressed by the user the
333
588
  *
334
- * permissions.
589
+ * corresponding handler will be invoked.
335
590
  *
336
- * Usage:
591
+ * This hook accepts 3 arguments hotkey, handler & config.
337
592
  *
338
593
  * @example
339
594
  *
340
- * hasAllPermissions("user.view_settings", "user.edit_settings");
595
+ * // openSidebar function will only be called if the user is focused inside the textarea and performs the key combination.
596
+ * const ref = useHotKeys("command+shift+r", openSidebar, {
597
+ * mode: "scoped",
598
+ * });
599
+ *
600
+ * return (
601
+ * <div>
602
+ * <div>Hello world</div>
603
+ * <textarea ref={ref}></textarea>
604
+ * </div>
605
+ * );
341
606
  * @endexample
342
607
  */
343
- export function hasAllPermissions(...permissions: string[]): boolean;
608
+ export function useHotKeys(hotkey: string | string[], handler: (event: React.KeyboardEvent) => void, config?: ConfigType): React.MutableRefObject | null;