@promoboxx/use-filter 1.7.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,375 @@
1
+ # @promoboxx/use-filter
2
+
3
+ A React hook to easily build filter views, with features like:
4
+
5
+ - persistence
6
+ - debouncing
7
+ - cursor based pagination
8
+ - offset / page based pagination
9
+
10
+ ## What's Included
11
+
12
+ The filter system providers you with a few things:
13
+
14
+ - `filter`: A key/value store for arbitrary filter values
15
+ - `filterInfo`: Metadata around your filter with the current page, number of results, total pages, cursor, etc
16
+ - `filterApi`: What is returned from the hook, complete with `filterInfo` and helpers to update values in your `filter`, change the page, etc.
17
+
18
+ ## Usage
19
+
20
+ There are two hooks provided. The default, "advanced", is more controlled, where you provide an `onChange` function which is called by the hook whenever you manipulate the filter.
21
+
22
+ The alternative, "simple", works similarly but gives you both `filterInfo` and a `debouncedFilterInfo` for you to use in effects.
23
+
24
+ ### Advanced Example
25
+
26
+ ```tsx
27
+ const { filterInfo, updateFilter, setPage, resetFilter, isLoading } = useFilter(
28
+ // Since this deals with caching, a namespace is required.
29
+ 'advanced',
30
+ {
31
+ // Disable this if you are using the hook's data caching.
32
+ shouldForceRunOnMount: true,
33
+
34
+ defaultFilterInfo: {
35
+ filter: {
36
+ name: '',
37
+ },
38
+ pageSize: 20,
39
+ },
40
+
41
+ // Called by the hook whenever the filter changes.
42
+ async onChange(
43
+ filterInfo,
44
+ // If this is called as a result of the filter changing, the reason will
45
+ // be 'filter', If it.s due to the page changing, it will be 'pagination'.
46
+ updateReason,
47
+ ) {
48
+ const { data } = await runQuery({
49
+ name: filterInfo.filter.name,
50
+ page: filterInfo.page,
51
+ })
52
+
53
+ // Here we are telling the filter system how many results there are. Since
54
+ // it knows how many we want to display per-page, it can now figure out
55
+ // how many pages there are in total.
56
+ return {
57
+ filterInfo: {
58
+ totalResults: data?.locations?.info.count,
59
+ },
60
+ }
61
+ },
62
+ },
63
+ )
64
+
65
+ return (
66
+ <>
67
+ <input
68
+ type="text"
69
+ value={filterInfo.filter.name}
70
+ onChange={(event) => {
71
+ updateFilter({ name: event.target.value })
72
+ }}
73
+ />
74
+
75
+ <button onClick={resetFilter}>Reset</button>
76
+
77
+ {isLoading ? <CircularProgress /> : undefined}
78
+
79
+ {/* Hypothetical list of results would be here */}
80
+
81
+ <Pagination
82
+ totalPages={filterInfo.totalPages}
83
+ page={filterInfo.page}
84
+ onPageChange={(page) => {
85
+ setPage(page)
86
+ }}
87
+ />
88
+ </>
89
+ )
90
+ ```
91
+
92
+ ### Simple Example
93
+
94
+ ```tsx
95
+ const {
96
+ filterInfo,
97
+ debouncedFilterInfo,
98
+ updateFilter,
99
+ pagingInfo,
100
+ setPage,
101
+ resetFilter,
102
+ isLoading,
103
+ } = useSimpleFilter('simple', {
104
+ defaultFilterInfo: {
105
+ filter: {
106
+ name: '',
107
+ },
108
+ pageSize: 20,
109
+ },
110
+ })
111
+
112
+ // Hypothetical fetch / query / graphql hook.
113
+ const { data, fetch } = useQuery()
114
+
115
+ useEffect(() => {
116
+ fetch({
117
+ name: debouncedFilterInfo.filter.name,
118
+ page: debouncedFilterInfo.page,
119
+ })
120
+ }, [debouncedFilterInfo])
121
+
122
+ // Since the simple mode doesn't know when we're done doing our work, it
123
+ // provides a helper to get us pagination info.
124
+ const { totalPages } = pagingInfo(data?.count)
125
+
126
+ return (
127
+ <>
128
+ <input
129
+ type="text"
130
+ value={filterInfo.filter.name}
131
+ onChange={(event) => {
132
+ updateFilter({ name: event.target.value })
133
+ }}
134
+ />
135
+
136
+ <button onClick={resetFilter}>Reset</button>
137
+
138
+ {isLoading ? <CircularProgress /> : undefined}
139
+
140
+ {/* Hypothetical list of results would be here */}
141
+
142
+ <Pagination
143
+ totalPages={totalPages}
144
+ page={filterInfo.page}
145
+ onPageChange={(page) => {
146
+ setPage(page)
147
+ }}
148
+ />
149
+ </>
150
+ )
151
+ ```
152
+
153
+ ## API
154
+
155
+ ### `useFilter(options)`
156
+
157
+ ```tsx
158
+ interface UseFilterOptions<TFilter, TResult> {
159
+ /**
160
+ * Default values for your filter. When calling `.reset` your filter will be
161
+ * set to this.
162
+ * Changing these values does not cause a call to happen.
163
+ */
164
+ defaultFilterInfo?: Partial<FilterInfo<TFilter>>
165
+
166
+ /**
167
+ * Enable this if you are not using the data caching of this hook.
168
+ */
169
+ shouldForceRunOnMount?: boolean
170
+
171
+ /**
172
+ * Called whenever the filter changes.
173
+ */
174
+ onChange: (
175
+ filterInfo: FilterInfo<TFilter>,
176
+ reason: UseFilterUpdateReason,
177
+ ) => MaybePromise<UseFilterOnChangeResult<TFilter, TResult>>
178
+
179
+ /**
180
+ * In case you want to change the default debounce duration.
181
+ */
182
+ debounceDuration?: number
183
+ }
184
+
185
+ export interface FilterApi<TFilter, TResult> {
186
+ /**
187
+ * Whether the system is debouncing or waiting for your `onChange` to finish.
188
+ */
189
+ isLoading: boolean
190
+ /**
191
+ * Any cached data for this filter.
192
+ */
193
+ data: TResult | null | undefined
194
+ /**
195
+ * Access to the filter and its metadata.
196
+ */
197
+ filterInfo: FilterInfo<TFilter>
198
+
199
+ /**
200
+ * Whether the filter existed in the system when the component mounted.
201
+ * @deprecated
202
+ */
203
+ doesFilterExist: boolean
204
+ /**
205
+ * Why the last update happened.
206
+ */
207
+ updateReason: UseFilterUpdateReason
208
+
209
+ /**
210
+ * Update one or more values in your filter.
211
+ */
212
+ updateFilter: (
213
+ filter: Partial<TFilter>,
214
+ shouldRunImmediately?: boolean,
215
+ ) => void
216
+
217
+ /**
218
+ * Resets the filter back to `defaultFilterInfo`.
219
+ */
220
+ resetFilter: (shouldRunImmediately?: boolean) => void
221
+
222
+ /**
223
+ * Changes the offset. Will update `page`.
224
+ */
225
+ setOffset: (offset: number | string, shouldRunImmediately?: boolean) => void
226
+
227
+ /**
228
+ * Changes the page. Will update `offset`.
229
+ */
230
+ setPage: (page: number | string, shouldRunImmediately?: boolean) => void
231
+
232
+ /**
233
+ * Changes the page size.
234
+ */
235
+ setPageSize: (
236
+ pageSize: number | string,
237
+ shouldRunImmediately?: boolean,
238
+ ) => void
239
+
240
+ /**
241
+ * Change the sort method.
242
+ */
243
+ setSort: (sort: string | undefined, shouldRunImmediately?: boolean) => void
244
+
245
+ /**
246
+ * Changes the cursor.
247
+ */
248
+ setCursor: (cursor: string | null | undefined) => void
249
+
250
+ /**
251
+ * Forces a refresh of the filter.
252
+ */
253
+ forceRefresh: (shouldRunImmediately?: boolean) => void
254
+ }
255
+
256
+ interface FilterInfo<TFilter> {
257
+ filter: TFilter
258
+ offset: number
259
+ page: number
260
+ sort?: string
261
+ pageSize: number
262
+ lastRefreshAt: number
263
+ totalResults: number
264
+ totalPages: number
265
+ shouldRunImmediately: boolean
266
+ cursor?: string | null
267
+ nextCursor?: string | null
268
+ }
269
+ ```
270
+
271
+ ### `useSimpleFilter(options)`
272
+
273
+ ```tsx
274
+ interface UseSimpleFilterOptions<TFilter> {
275
+ /**
276
+ * Default values for your filter. When calling `.reset` your filter will be
277
+ * set to this.
278
+ * Changing these values does not cause a call to happen.
279
+ */
280
+ defaultFilterInfo?: Partial<SimpleFilterInfo<TFilter>>
281
+
282
+ /**
283
+ * In case you want to change the default debounce duration.
284
+ */
285
+ debounceDuration?: number
286
+ }
287
+
288
+ export interface SimpleFilterApi<TFilter> {
289
+ /**
290
+ * Really more "is debouncing", since simple mode doesn't know when your code
291
+ * is doing anything.
292
+ */
293
+ isLoading: boolean
294
+ /**
295
+ * Access to the filter and its metadata.
296
+ */
297
+ filterInfo: SimpleFilterInfo<TFilter>
298
+ /**
299
+ * Same as the regular `filterInfo`, but updates in a debounced fashion.
300
+ */
301
+ debouncedFilterInfo: SimpleFilterInfo<TFilter>
302
+ /**
303
+ * Why the last update happened.
304
+ */
305
+ updateReason: UseFilterUpdateReason
306
+
307
+ /**
308
+ * Update one or more values in your filter.
309
+ */
310
+ updateFilter: (
311
+ filter: Partial<TFilter>,
312
+ shouldRunImmediately?: boolean,
313
+ ) => void
314
+
315
+ /**
316
+ * Does the boring math for you based on your `pageSize` and `totalResults`.
317
+ */
318
+ pagingInfo: (total: string | number | null | undefined) => {
319
+ totalResults: number
320
+ totalPages: number
321
+ }
322
+
323
+ /**
324
+ * Resets the filter back to `defaultFilterInfo`.
325
+ */
326
+ resetFilter: (shouldRunImmediately?: boolean) => void
327
+
328
+ /**
329
+ * Changes the offset. Will update `page`.
330
+ */
331
+ setOffset: (offset: number | string, shouldRunImmediately?: boolean) => void
332
+
333
+ /**
334
+ * Changes the page. Will update `offset`.
335
+ */
336
+ setPage: (page: number | string, shouldRunImmediately?: boolean) => void
337
+
338
+ /**
339
+ * Changes the page size.
340
+ */
341
+ setPageSize: (
342
+ pageSize: number | string,
343
+ shouldRunImmediately?: boolean,
344
+ ) => void
345
+
346
+ /**
347
+ * Change the sort method.
348
+ */
349
+ setSort: (sort: string, shouldRunImmediately?: boolean) => void
350
+
351
+ /**
352
+ * Changes the cursor.
353
+ */
354
+ setCursor: (
355
+ cursor: string | null | undefined,
356
+ shouldRunImmediately?: boolean,
357
+ ) => void
358
+
359
+ /**
360
+ * Forces a refresh of the filter.
361
+ */
362
+ forceRefresh: (shouldRunImmediately?: boolean) => void
363
+ }
364
+
365
+ interface SimpleFilterInfo<TFilter> {
366
+ filter: TFilter
367
+ sort?: string
368
+ offset: number
369
+ page: number
370
+ pageSize: number
371
+ lastRefreshAt: number
372
+ cursor?: string | null
373
+ shouldRunImmediately: boolean
374
+ }
375
+ ```
@@ -1,24 +1,81 @@
1
1
  declare type MaybePromise<T> = T | Promise<T>;
2
2
  interface UseFilterOptions<TFilter, TResult> {
3
+ /**
4
+ * Default values for your filter. When calling `.reset` your filter will be
5
+ * set to this.
6
+ * Changing these values does not cause a call to happen.
7
+ */
3
8
  defaultFilterInfo?: Partial<FilterInfo<TFilter>>;
9
+ /**
10
+ * Enable this if you are not using the data caching of this hook.
11
+ */
4
12
  shouldForceRunOnMount?: boolean;
5
- onChange: (filterInfo: FilterInfo<TFilter>) => MaybePromise<UseFilterOnChangeResult<TFilter, TResult>>;
13
+ /**
14
+ * Called whenever the filter changes.
15
+ */
16
+ onChange: (filterInfo: FilterInfo<TFilter>, reason: UseFilterUpdateReason) => MaybePromise<UseFilterOnChangeResult<TFilter, TResult>>;
17
+ /**
18
+ * In case you want to change the default debounce duration.
19
+ */
6
20
  debounceDuration?: number;
7
21
  }
8
- declare function useFilter<TFilter, TResult>(namespace: string, options: UseFilterOptions<TFilter, TResult>): {
22
+ export interface FilterApi<TFilter, TResult> {
23
+ /**
24
+ * Whether the system is debouncing or waiting for your `onChange` to finish.
25
+ */
9
26
  isLoading: boolean;
27
+ /**
28
+ * Any cached data for this filter.
29
+ */
10
30
  data: TResult | null | undefined;
11
- doesFilterExist: boolean;
31
+ /**
32
+ * Access to the filter and its metadata.
33
+ */
12
34
  filterInfo: FilterInfo<TFilter>;
35
+ /**
36
+ * Whether the filter existed in the system when the component mounted.
37
+ * @deprecated
38
+ */
39
+ doesFilterExist: boolean;
40
+ /**
41
+ * Why the last update happened.
42
+ */
43
+ updateReason: UseFilterUpdateReason;
44
+ /**
45
+ * Update one or more values in your filter.
46
+ */
13
47
  updateFilter: (filter: Partial<TFilter>, shouldRunImmediately?: boolean) => void;
48
+ /**
49
+ * Resets the filter back to `defaultFilterInfo`.
50
+ */
14
51
  resetFilter: (shouldRunImmediately?: boolean) => void;
52
+ /**
53
+ * Changes the offset. Will update `page`.
54
+ */
15
55
  setOffset: (offset: number | string, shouldRunImmediately?: boolean) => void;
56
+ /**
57
+ * Changes the page. Will update `offset`.
58
+ */
16
59
  setPage: (page: number | string, shouldRunImmediately?: boolean) => void;
60
+ /**
61
+ * Changes the page size.
62
+ */
17
63
  setPageSize: (pageSize: number | string, shouldRunImmediately?: boolean) => void;
64
+ /**
65
+ * Change the sort method.
66
+ */
18
67
  setSort: (sort: string | undefined, shouldRunImmediately?: boolean) => void;
19
- setCursor: (cursor: string | null | undefined, shouldRunImmediately?: boolean) => void;
68
+ /**
69
+ * Changes the cursor.
70
+ */
71
+ setCursor: (cursor: string | null | undefined) => void;
72
+ /**
73
+ * Forces a refresh of the filter.
74
+ */
20
75
  forceRefresh: (shouldRunImmediately?: boolean) => void;
21
- };
76
+ }
77
+ export declare type UseFilterUpdateReason = 'initial' | 'filter' | 'pagination';
78
+ declare function useFilter<TFilter, TResult>(namespace: string, options: UseFilterOptions<TFilter, TResult>): FilterApi<TFilter, TResult>;
22
79
  export default useFilter;
23
80
  export interface FilterInfo<TFilter> {
24
81
  filter: TFilter;
package/dist/useFilter.js CHANGED
@@ -64,6 +64,7 @@ function useFilter(namespace, options) {
64
64
  : filterInfo
65
65
  ? filterInfo.lastRefreshAt
66
66
  : -1);
67
+ var updateReasonRef = react_1.useRef('initial');
67
68
  // Call onChange when data changes.
68
69
  react_1.useEffect(function () {
69
70
  setIsLoading(true);
@@ -80,7 +81,7 @@ function useFilter(namespace, options) {
80
81
  }
81
82
  var makeRequest = function () {
82
83
  lastRefreshAtRef.current = filterInfo.lastRefreshAt;
83
- var response = ctxRef.current.onChange(filterInfo);
84
+ var response = ctxRef.current.onChange(filterInfo, updateReasonRef.current);
84
85
  store_1.getFilterStore().saveFilter(namespace, filterInfo);
85
86
  if (!response) {
86
87
  setIsLoading(false);
@@ -148,13 +149,15 @@ function useFilter(namespace, options) {
148
149
  }
149
150
  };
150
151
  }, [filterInfo, namespace]);
151
- return {
152
+ var api = {
152
153
  isLoading: isLoading,
153
154
  data: data,
154
155
  doesFilterExist: doesFilterExist.current,
155
156
  filterInfo: filterInfo || buildDefaultFilterInfo_1.default(options.defaultFilterInfo),
157
+ updateReason: updateReasonRef.current,
156
158
  updateFilter: react_1.useCallback(function (filter, shouldRunImmediately) {
157
159
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
160
+ updateReasonRef.current = 'filter';
158
161
  setFilterInfoState(function (previous) {
159
162
  invariant(previous != null, 'updateFilter called without filterInfo');
160
163
  var nextFilter = __assign(__assign({}, previous.filter), filter);
@@ -166,10 +169,12 @@ function useFilter(namespace, options) {
166
169
  }, []),
167
170
  resetFilter: react_1.useCallback(function (shouldRunImmediately) {
168
171
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
172
+ updateReasonRef.current = 'filter';
169
173
  setFilterInfoState(__assign(__assign({}, buildDefaultFilterInfo_1.default(ctxRef.current.defaultFilterInfo)), { lastRefreshAt: new Date().getTime(), shouldRunImmediately: shouldRunImmediately }));
170
174
  }, []),
171
175
  setOffset: react_1.useCallback(function (offset, shouldRunImmediately) {
172
176
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
177
+ updateReasonRef.current = 'pagination';
173
178
  setFilterInfoState(function (previous) {
174
179
  invariant(previous != null, 'setOffset called without filterInfo');
175
180
  var offsetNumber = Number(offset);
@@ -178,6 +183,7 @@ function useFilter(namespace, options) {
178
183
  }, []),
179
184
  setPage: react_1.useCallback(function (page, shouldRunImmediately) {
180
185
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
186
+ updateReasonRef.current = 'pagination';
181
187
  setFilterInfoState(function (previous) {
182
188
  invariant(previous != null, 'setPage called without filterInfo');
183
189
  var pageNumber = Number(page);
@@ -186,6 +192,7 @@ function useFilter(namespace, options) {
186
192
  }, []),
187
193
  setPageSize: react_1.useCallback(function (pageSize, shouldRunImmediately) {
188
194
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
195
+ updateReasonRef.current = 'pagination';
189
196
  setFilterInfoState(function (previous) {
190
197
  invariant(previous != null, 'setPageSize called without filterInfo');
191
198
  var pageSizeNumber = Number(pageSize);
@@ -196,6 +203,7 @@ function useFilter(namespace, options) {
196
203
  }, []),
197
204
  setSort: react_1.useCallback(function (sort, shouldRunImmediately) {
198
205
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
206
+ updateReasonRef.current = 'filter';
199
207
  setFilterInfoState(function (previous) {
200
208
  invariant(previous != null, 'setSort called without filterInfo');
201
209
  return __assign(__assign({}, previous), { sort: sort, lastRefreshAt: new Date().getTime(), shouldRunImmediately: shouldRunImmediately });
@@ -204,18 +212,21 @@ function useFilter(namespace, options) {
204
212
  setCursor: react_1.useCallback(function (cursor, shouldRunImmediately) {
205
213
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
206
214
  setFilterInfoState(function (previous) {
215
+ updateReasonRef.current = 'pagination';
207
216
  invariant(previous != null, 'setCursor called without filterInfo');
208
217
  return __assign(__assign({}, previous), { cursor: cursor, lastRefreshAt: new Date().getTime(), shouldRunImmediately: shouldRunImmediately });
209
218
  });
210
219
  }, []),
211
220
  forceRefresh: react_1.useCallback(function (shouldRunImmediately) {
212
221
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
222
+ updateReasonRef.current = 'filter';
213
223
  setFilterInfoState(function (previous) {
214
224
  invariant(previous != null, 'forceRefresh called without filterInfo');
215
225
  return __assign(__assign({}, previous), { lastRefreshAt: new Date().getTime(), shouldRunImmediately: shouldRunImmediately });
216
226
  });
217
227
  }, []),
218
228
  };
229
+ return api;
219
230
  }
220
231
  exports.default = useFilter;
221
232
  function invariant(input, message) {
@@ -1,50 +1,83 @@
1
- export interface SimpleFilterInfo<TFilter> {
2
- filter: TFilter;
3
- sort?: string;
4
- offset: number;
5
- page: number;
6
- pageSize: number;
7
- lastRefreshAt: number;
8
- cursor?: string | null;
9
- shouldRunImmediately: boolean;
10
- }
1
+ import { UseFilterUpdateReason } from './useFilter';
11
2
  interface UseSimpleFilterOptions<TFilter> {
3
+ /**
4
+ * Default values for your filter. When calling `.reset` your filter will be
5
+ * set to this.
6
+ * Changing these values does not cause a call to happen.
7
+ */
12
8
  defaultFilterInfo?: Partial<SimpleFilterInfo<TFilter>>;
9
+ /**
10
+ * In case you want to change the default debounce duration.
11
+ */
13
12
  debounceDuration?: number;
14
13
  }
15
- declare function useSimpleFilter<TFilter>(namespace: string, options: UseSimpleFilterOptions<TFilter>): {
14
+ export interface SimpleFilterApi<TFilter> {
15
+ /**
16
+ * Really more "is debouncing", since simple mode doesn't know when your code
17
+ * is doing anything.
18
+ */
16
19
  isLoading: boolean;
17
- filterInfo: {
18
- shouldRunImmediately: boolean;
19
- filter: TFilter;
20
- sort?: string | undefined;
21
- offset: number;
22
- page: number;
23
- pageSize: number;
24
- lastRefreshAt: number;
25
- cursor?: string | null | undefined;
26
- };
27
- debouncedFilterInfo: {
28
- shouldRunImmediately: boolean;
29
- filter: TFilter;
30
- sort?: string | undefined;
31
- offset: number;
32
- page: number;
33
- pageSize: number;
34
- lastRefreshAt: number;
35
- cursor?: string | null | undefined;
36
- };
37
- updateFilter: (filter: Partial<TFilter>, shouldRunImmediately?: any) => void;
20
+ /**
21
+ * Access to the filter and its metadata.
22
+ */
23
+ filterInfo: SimpleFilterInfo<TFilter>;
24
+ /**
25
+ * Same as the regular `filterInfo`, but updates in a debounced fashion.
26
+ */
27
+ debouncedFilterInfo: SimpleFilterInfo<TFilter>;
28
+ /**
29
+ * Why the last update happened.
30
+ */
31
+ updateReason: UseFilterUpdateReason;
32
+ /**
33
+ * Update one or more values in your filter.
34
+ */
35
+ updateFilter: (filter: Partial<TFilter>, shouldRunImmediately?: boolean) => void;
36
+ /**
37
+ * Does the boring math for you based on your `pageSize` and `totalResults`.
38
+ */
38
39
  pagingInfo: (total: string | number | null | undefined) => {
39
40
  totalResults: number;
40
41
  totalPages: number;
41
42
  };
43
+ /**
44
+ * Resets the filter back to `defaultFilterInfo`.
45
+ */
42
46
  resetFilter: (shouldRunImmediately?: boolean) => void;
47
+ /**
48
+ * Changes the offset. Will update `page`.
49
+ */
43
50
  setOffset: (offset: number | string, shouldRunImmediately?: boolean) => void;
51
+ /**
52
+ * Changes the page. Will update `offset`.
53
+ */
44
54
  setPage: (page: number | string, shouldRunImmediately?: boolean) => void;
55
+ /**
56
+ * Changes the page size.
57
+ */
45
58
  setPageSize: (pageSize: number | string, shouldRunImmediately?: boolean) => void;
59
+ /**
60
+ * Change the sort method.
61
+ */
46
62
  setSort: (sort: string, shouldRunImmediately?: boolean) => void;
63
+ /**
64
+ * Changes the cursor.
65
+ */
47
66
  setCursor: (cursor: string | null | undefined, shouldRunImmediately?: boolean) => void;
67
+ /**
68
+ * Forces a refresh of the filter.
69
+ */
48
70
  forceRefresh: (shouldRunImmediately?: boolean) => void;
49
- };
71
+ }
72
+ export interface SimpleFilterInfo<TFilter> {
73
+ filter: TFilter;
74
+ sort?: string;
75
+ offset: number;
76
+ page: number;
77
+ pageSize: number;
78
+ lastRefreshAt: number;
79
+ cursor?: string | null;
80
+ shouldRunImmediately: boolean;
81
+ }
82
+ declare function useSimpleFilter<TFilter>(namespace: string, options: UseSimpleFilterOptions<TFilter>): SimpleFilterApi<TFilter>;
50
83
  export default useSimpleFilter;
@@ -37,6 +37,7 @@ function useSimpleFilter(namespace, options) {
37
37
  var _c = react_1.useState(filterInfo), debouncedFilterInfo = _c[0], setDebouncedFilterInfo = _c[1];
38
38
  // Not sure this is needed in simple mode?
39
39
  var lastRefreshAtRef = react_1.useRef(-1);
40
+ var updateReasonRef = react_1.useRef('initial');
40
41
  react_1.useEffect(function () {
41
42
  var _a;
42
43
  setIsLoading(true);
@@ -65,12 +66,14 @@ function useSimpleFilter(namespace, options) {
65
66
  };
66
67
  }, [filterInfo]);
67
68
  var previousTotalRef = react_1.useRef(0);
68
- return {
69
+ var api = {
69
70
  isLoading: isLoading,
70
71
  filterInfo: filterInfo,
71
72
  debouncedFilterInfo: debouncedFilterInfo,
73
+ updateReason: updateReasonRef.current,
72
74
  updateFilter: react_1.useCallback(function (filter, shouldRunImmediately) {
73
75
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
76
+ updateReasonRef.current = 'filter';
74
77
  setFilterInfoState(function (previous) {
75
78
  var nextFilter = __assign(__assign({}, previous.filter), filter);
76
79
  if (shallowEqual_1.default(previous.filter, nextFilter)) {
@@ -92,20 +95,24 @@ function useSimpleFilter(namespace, options) {
92
95
  }, [filterInfo.pageSize]),
93
96
  resetFilter: react_1.useCallback(function (shouldRunImmediately) {
94
97
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
98
+ updateReasonRef.current = 'filter';
95
99
  setFilterInfoState(__assign(__assign({}, buildDefaultFilterInfo(ctxRef.current.defaultFilterInfo)), { shouldRunImmediately: shouldRunImmediately }));
96
100
  }, []),
97
101
  setOffset: react_1.useCallback(function (offset, shouldRunImmediately) {
98
102
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
103
+ updateReasonRef.current = 'pagination';
99
104
  var offsetNumber = Number(offset);
100
105
  setFilterInfoState(function (previous) { return (__assign(__assign({}, previous), { offset: offsetNumber, page: getPageFromOffset_1.default(offsetNumber, previous.pageSize), lastRefreshAt: new Date().getTime(), shouldRunImmediately: shouldRunImmediately })); });
101
106
  }, []),
102
107
  setPage: react_1.useCallback(function (page, shouldRunImmediately) {
103
108
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
109
+ updateReasonRef.current = 'pagination';
104
110
  var pageNumber = Number(page);
105
111
  setFilterInfoState(function (previous) { return (__assign(__assign({}, previous), { offset: getOffsetFromPage_1.default(pageNumber, previous.pageSize), page: pageNumber, lastRefreshAt: new Date().getTime(), shouldRunImmediately: shouldRunImmediately })); });
106
112
  }, []),
107
113
  setPageSize: react_1.useCallback(function (pageSize, shouldRunImmediately) {
108
114
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
115
+ updateReasonRef.current = 'pagination';
109
116
  setFilterInfoState(function (previous) {
110
117
  var pageSizeNumber = Number(pageSize);
111
118
  var page = getPageFromOffset_1.default(previous.offset, pageSizeNumber);
@@ -115,17 +122,21 @@ function useSimpleFilter(namespace, options) {
115
122
  }, []),
116
123
  setSort: react_1.useCallback(function (sort, shouldRunImmediately) {
117
124
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
125
+ updateReasonRef.current = 'filter';
118
126
  setFilterInfoState(function (previous) { return (__assign(__assign({}, previous), { sort: sort, lastRefreshAt: new Date().getTime(), shouldRunImmediately: shouldRunImmediately })); });
119
127
  }, []),
120
128
  setCursor: react_1.useCallback(function (cursor, shouldRunImmediately) {
121
129
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
130
+ updateReasonRef.current = 'pagination';
122
131
  setFilterInfoState(function (previous) { return (__assign(__assign({}, previous), { cursor: cursor, lastRefreshAt: new Date().getTime(), shouldRunImmediately: shouldRunImmediately })); });
123
132
  }, []),
124
133
  forceRefresh: react_1.useCallback(function (shouldRunImmediately) {
125
134
  if (shouldRunImmediately === void 0) { shouldRunImmediately = false; }
135
+ updateReasonRef.current = 'filter';
126
136
  setFilterInfoState(function (previous) { return (__assign(__assign({}, previous), { lastRefreshAt: new Date().getTime(), shouldRunImmediately: shouldRunImmediately })); });
127
137
  }, []),
128
138
  };
139
+ return api;
129
140
  }
130
141
  function buildDefaultFilterInfo(filterInfo) {
131
142
  if (filterInfo === void 0) { filterInfo = {}; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promoboxx/use-filter",
3
- "version": "1.7.0",
3
+ "version": "1.8.1",
4
4
  "description": "",
5
5
  "main": "dist/useFilter.js",
6
6
  "keywords": [],