@websolutespa/bom-mixer-hooks 1.8.11 → 1.9.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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @websolutespa/bom-mixer-hooks
2
2
 
3
+ ## 1.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Modified: usePagination
8
+ - Added: useMetaData
9
+
3
10
  ## 1.8.11
4
11
 
5
12
  ### Patch Changes
package/README.md CHANGED
@@ -9,3 +9,433 @@ Mixer Hooks module of the [BOM Repository](https://github.com/websolutespa/bom)
9
9
  ---
10
10
 
11
11
  ##### *this library is for internal usage and not production ready*
12
+
13
+ # @websolutespa/bom-mixer-hooks Documentation
14
+
15
+ A collection of React hooks for building modern web applications.
16
+
17
+ ## Table of Contents
18
+
19
+ - [Installation](#installation)
20
+ - [API and Networking](#api-and-networking)
21
+ - [UI and Layout](#ui-and-layout)
22
+ - [Form and Input](#form-and-input)
23
+ - [Internationalization](#internationalization)
24
+ - [Scroll and Viewport](#scroll-and-viewport)
25
+ - [State Management](#state-management)
26
+ - [Performance](#performance)
27
+ - [Event Handling](#event-handling)
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install @websolutespa/bom-mixer-hooks
33
+ ```
34
+
35
+ ## API and Networking
36
+
37
+ ### useApi
38
+
39
+ Hook for making RESTful API calls.
40
+
41
+ ```typescript
42
+ import { useApi } from '@websolutespa/bom-mixer-hooks';
43
+
44
+ function MyComponent() {
45
+ const api = useApi();
46
+
47
+ const fetchData = async () => {
48
+ try {
49
+ // GET request
50
+ const data = await api.get('/endpoint');
51
+
52
+ // POST request with payload
53
+ const response = await api.post('/endpoint', {
54
+ name: 'John',
55
+ });
56
+
57
+ // PUT request
58
+ await api.put('/endpoint/1', {
59
+ updated: true,
60
+ });
61
+
62
+ // DELETE request
63
+ await api.delete('/endpoint/1');
64
+ } catch (error) {
65
+ console.error('API error:', error);
66
+ }
67
+ };
68
+ }
69
+ ```
70
+
71
+ ### useCollectionApi
72
+
73
+ Specialized version of useApi for data collections.
74
+
75
+ ```typescript
76
+ import { useCollectionApi, useCollectionApiGet } from '@websolutespa/bom-mixer-hooks';
77
+
78
+ function MyCollection() {
79
+ const [data, loading, error] = useCollectionApiGet('/collection', {
80
+ where: { status: 'active' }
81
+ });
82
+
83
+ if (loading) return <Loading />;
84
+ if (error) return <Error message={error.message} />;
85
+
86
+ return (
87
+ <div>
88
+ {data.map(item => (
89
+ <Item key={item.id} {...item} />
90
+ ))}
91
+ </div>
92
+ );
93
+ }
94
+ ```
95
+
96
+ ## UI and Layout
97
+
98
+ ### useLayout
99
+
100
+ Manages the global application layout.
101
+
102
+ ```typescript
103
+ import { useLayout } from '@websolutespa/bom-mixer-hooks';
104
+
105
+ function Header() {
106
+ const layout = useLayout();
107
+
108
+ return (
109
+ <header>
110
+ <nav>
111
+ {layout.menu.main.items.map(item => (
112
+ <MenuItem key={item.id} {...item} />
113
+ ))}
114
+ </nav>
115
+ </header>
116
+ );
117
+ }
118
+ ```
119
+
120
+ ### useDrawer
121
+
122
+ Manages drawer/sidebar state.
123
+
124
+ ```typescript
125
+ import { useDrawer } from '@websolutespa/bom-mixer-hooks';
126
+
127
+ function Sidebar() {
128
+ const [drawer, openDrawer, closeDrawer] = useDrawer();
129
+
130
+ return (
131
+ <>
132
+ <button onClick={() => openDrawer('main')}>Open Menu</button>
133
+
134
+ <div className={`drawer ${drawer === 'main' ? 'open' : ''}`}>
135
+ <button onClick={closeDrawer}>Close</button>
136
+ {/* Drawer content */}
137
+ </div>
138
+ </>
139
+ );
140
+ }
141
+ ```
142
+
143
+ ### useBreakpoint
144
+
145
+ Handles responsive breakpoints.
146
+
147
+ ```typescript
148
+ import { useBreakpoint } from '@websolutespa/bom-mixer-hooks';
149
+
150
+ function ResponsiveComponent() {
151
+ const breakpoint = useBreakpoint();
152
+
153
+ return (
154
+ <div>
155
+ {breakpoint.key === 'xs' && <MobileView />}
156
+ {breakpoint.key === 'md' && <TabletView />}
157
+ {breakpoint.key === 'lg' && <DesktopView />}
158
+ </div>
159
+ );
160
+ }
161
+ ```
162
+
163
+ ## Form and Input
164
+
165
+ ### useAutosizeTextArea
166
+
167
+ Automatically adjusts textarea height.
168
+
169
+ ```typescript
170
+ import { useAutosizeTextArea } from '@websolutespa/bom-mixer-hooks';
171
+
172
+ function AutoResizingTextarea() {
173
+ const [value, setValue] = useState('');
174
+ const textAreaRef = useRef<HTMLTextAreaElement>(null);
175
+
176
+ useAutosizeTextArea(textAreaRef.current, value);
177
+
178
+ return (
179
+ <textarea
180
+ ref={textAreaRef}
181
+ value={value}
182
+ onChange={(e) => setValue(e.target.value)}
183
+ />
184
+ );
185
+ }
186
+ ```
187
+
188
+ ### useFocusTrap
189
+
190
+ Keeps focus within an element (useful for modals).
191
+
192
+ ```typescript
193
+ import { useFocusTrap } from '@websolutespa/bom-mixer-hooks';
194
+
195
+ function Modal() {
196
+ const modalRef = useRef(null);
197
+ const [isTrapped, setIsTrapped] = useFocusTrap(modalRef);
198
+
199
+ useEffect(() => {
200
+ setIsTrapped(true);
201
+ return () => setIsTrapped(false);
202
+ }, []);
203
+
204
+ return (
205
+ <div ref={modalRef}>
206
+ <input type="text" />
207
+ <button>Action</button>
208
+ <button>Close</button>
209
+ </div>
210
+ );
211
+ }
212
+ ```
213
+
214
+ ## Internationalization
215
+
216
+ ### useLabel
217
+
218
+ Manages translations.
219
+
220
+ ```typescript
221
+ import { useLabel } from '@websolutespa/bom-mixer-hooks';
222
+
223
+ function Translated() {
224
+ const label = useLabel();
225
+
226
+ return (
227
+ <div>
228
+ <h1>{label('welcome.title')}</h1>
229
+ <p>{label('welcome.description', { name: 'John' })}</p>
230
+ </div>
231
+ );
232
+ }
233
+ ```
234
+
235
+ ### useCurrency
236
+
237
+ Formats monetary values.
238
+
239
+ ```typescript
240
+ import { useCurrency } from '@websolutespa/bom-mixer-hooks';
241
+
242
+ function PriceDisplay() {
243
+ const formatCurrency = useCurrency('EUR', 'en-US');
244
+
245
+ return (
246
+ <div>
247
+ <p>Price: {formatCurrency(29.99)}</p> {/* Outputs: €29.99 */}
248
+ </div>
249
+ );
250
+ }
251
+ ```
252
+
253
+ ## Scroll and Viewport
254
+
255
+ ### useIntersectionObserver
256
+
257
+ Observes when elements enter the viewport.
258
+
259
+ ```typescript
260
+ import { useIntersectionObserver } from '@websolutespa/bom-mixer-hooks';
261
+
262
+ function LazyImage() {
263
+ const ref = useRef(null);
264
+ const isVisible = useIntersectionObserver(ref, {
265
+ threshold: 0.1
266
+ });
267
+
268
+ return (
269
+ <div ref={ref}>
270
+ {isVisible && <img src="heavy-image.jpg" alt="Lazy loaded" />}
271
+ </div>
272
+ );
273
+ }
274
+ ```
275
+
276
+ ### useScrollTo
277
+
278
+ Manages smooth scrolling to elements.
279
+
280
+ ```typescript
281
+ import { useScrollTo } from '@websolutespa/bom-mixer-hooks';
282
+
283
+ function ScrollableContent() {
284
+ const scrollTo = useScrollTo(80); // 80px offset
285
+
286
+ return (
287
+ <nav>
288
+ <a href="#section1" onClick={scrollTo}>Go to Section 1</a>
289
+ <div id="section1">
290
+ {/* Content */}
291
+ </div>
292
+ </nav>
293
+ );
294
+ }
295
+ ```
296
+
297
+ ## State Management
298
+
299
+ ### useCurrentState
300
+
301
+ Manages state with current reference.
302
+
303
+ ```typescript
304
+ import { useCurrentState } from '@websolutespa/bom-mixer-hooks';
305
+
306
+ function StateManager() {
307
+ const [value, setValue, valueRef] = useCurrentState(0);
308
+
309
+ useEffect(() => {
310
+ // valueRef.current is always up to date
311
+ const interval = setInterval(() => {
312
+ console.log('Current value:', valueRef.current);
313
+ }, 1000);
314
+
315
+ return () => clearInterval(interval);
316
+ }, []);
317
+
318
+ return (
319
+ <button onClick={() => setValue(v => v + 1)}>
320
+ Count: {value}
321
+ </button>
322
+ );
323
+ }
324
+ ```
325
+
326
+ ## Performance
327
+
328
+ ### useDebounce
329
+
330
+ Delays function execution.
331
+
332
+ ```typescript
333
+ import { useDebounce } from '@websolutespa/bom-mixer-hooks';
334
+
335
+ function SearchInput() {
336
+ const [value, setValue] = useState('');
337
+ const debouncedValue = useDebounce(value, 500);
338
+
339
+ useEffect(() => {
340
+ // API call only after 500ms from last input
341
+ searchAPI(debouncedValue);
342
+ }, [debouncedValue]);
343
+
344
+ return (
345
+ <input
346
+ type="text"
347
+ value={value}
348
+ onChange={(e) => setValue(e.target.value)}
349
+ />
350
+ );
351
+ }
352
+ ```
353
+
354
+ ## Event Handling
355
+
356
+ ### useEventListener
357
+
358
+ Safely manages event listeners.
359
+
360
+ ```typescript
361
+ import { useEventListener } from '@websolutespa/bom-mixer-hooks';
362
+
363
+ function EventHandler() {
364
+ const handleKeyPress = (e: KeyboardEvent) => {
365
+ if (e.key === 'Escape') {
366
+ // Handle escape key
367
+ }
368
+ };
369
+
370
+ useEventListener('keydown', handleKeyPress);
371
+
372
+ return <div>Press ESC to trigger action</div>;
373
+ }
374
+ ```
375
+
376
+ ## Best Practices
377
+
378
+ 1. **Hook Composition**
379
+
380
+ ```typescript
381
+ function ComplexComponent() {
382
+ const layout = useLayout();
383
+ const breakpoint = useBreakpoint();
384
+ const [drawer] = useDrawer();
385
+
386
+ // Combine hooks for advanced functionality
387
+ const isMobileMenuOpen = breakpoint.key === 'xs' && drawer === 'menu';
388
+
389
+ return (
390
+ <div className={isMobileMenuOpen ? 'mobile-menu' : ''}>
391
+ {/* Component content */}
392
+ </div>
393
+ );
394
+ }
395
+ ```
396
+
397
+ 2. **Error Handling**
398
+
399
+ ```typescript
400
+ function DataFetcher() {
401
+ const [data, loading, error] = useCollectionApiGet('/api/data');
402
+
403
+ if (error) {
404
+ return <ErrorBoundary error={error} />;
405
+ }
406
+
407
+ if (loading) {
408
+ return <LoadingSpinner />;
409
+ }
410
+
411
+ return <DataDisplay data={data} />;
412
+ }
413
+ ```
414
+
415
+ 3. **Performance Optimization**
416
+
417
+ ```typescript
418
+ function OptimizedComponent() {
419
+ const debouncedSearch = useDebounceCallback((term: string) => {
420
+ searchAPI(term);
421
+ }, 300);
422
+
423
+ const intersectionRef = useRef(null);
424
+ const isVisible = useIntersectionObserver(intersectionRef);
425
+
426
+ // Load heavy content only when visible
427
+ return (
428
+ <div ref={intersectionRef}>
429
+ {isVisible && <HeavyContent />}
430
+ </div>
431
+ );
432
+ }
433
+ ```
434
+
435
+ ## Contributing
436
+
437
+ Please read our [Contributing Guide](CONTRIBUTING.md) before submitting a Pull Request to the project.
438
+
439
+ ## License
440
+
441
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ import * as _websolutespa_bom_core from '@websolutespa/bom-core';
5
5
  import { QueryParams, IEquatable, IFeatureType, ILabel, ILocalizable, ILayout, ILocalized, IPage } from '@websolutespa/bom-core';
6
6
  import * as zustand from 'zustand';
7
7
  import * as react_jsx_runtime from 'react/jsx-runtime';
8
- import { ILazyModules } from '@websolutespa/bom-mixer-models';
8
+ import { ILazyModules, IMetaData, StructuredDataType, OpenGraphType, TwitterCardType } from '@websolutespa/bom-mixer-models';
9
9
  import { NextRouter } from 'next/router';
10
10
 
11
11
  declare function useApiFetch<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any, react.Dispatch<any>];
@@ -405,6 +405,34 @@ declare function LazyModulesProvider({ children, modules }: {
405
405
  modules: ILazyModules;
406
406
  }): react_jsx_runtime.JSX.Element;
407
407
 
408
+ type IMetaDataContext = IMetaData;
409
+ declare const useMetaData: () => IMetaData;
410
+ declare function MetaDataProvider({ children, metaData }: {
411
+ children?: react__default.ReactNode;
412
+ metaData: {
413
+ brand: {
414
+ name: string;
415
+ logo: string;
416
+ businessName?: string;
417
+ appName?: string;
418
+ url?: string;
419
+ email?: string;
420
+ telephone?: string;
421
+ zipCode?: string;
422
+ address?: string;
423
+ city?: string;
424
+ provinceCode?: string;
425
+ countryName?: string;
426
+ countryCode?: string;
427
+ twitterName?: string;
428
+ social?: Record<string, string>;
429
+ };
430
+ structuredData?: StructuredDataType;
431
+ openGraph?: OpenGraphType;
432
+ twitterCard?: TwitterCardType;
433
+ };
434
+ }): react_jsx_runtime.JSX.Element;
435
+
408
436
  declare function useModal(): [modal: UIValue, open: (value?: string) => void, close: () => void];
409
437
 
410
438
  declare function useMounted(): boolean;
@@ -444,6 +472,26 @@ declare const usePage: () => {
444
472
  description?: string | undefined;
445
473
  keywords?: string | undefined;
446
474
  robots?: string | undefined;
475
+ image?: {
476
+ [x: string]: unknown;
477
+ id?: string | undefined;
478
+ alt?: string | undefined;
479
+ filename?: string | undefined;
480
+ mimeType?: string | undefined;
481
+ filesize?: number | undefined;
482
+ focalX?: number | undefined;
483
+ focalY?: number | undefined;
484
+ createdAt?: string | Date | undefined;
485
+ updatedAt?: string | Date | undefined;
486
+ url?: string | undefined;
487
+ title?: string | undefined;
488
+ abstract?: string | undefined;
489
+ type: string;
490
+ src?: string | undefined;
491
+ media?: any | undefined;
492
+ width?: string | number | undefined;
493
+ height?: string | number | undefined;
494
+ } | undefined;
447
495
  } | undefined;
448
496
  components?: _websolutespa_bom_core.IComponent[] | undefined;
449
497
  category: {
@@ -792,18 +840,53 @@ declare function usePageLoading(options?: {
792
840
  previousPageRoute: IPageRoute | undefined;
793
841
  };
794
842
 
795
- type IPaginationInfo<T = any> = {
843
+ type IPaginationItem = any;
844
+ type IPaginationOptions = {
845
+ mode?: 'pagination' | 'infinite';
846
+ page?: number;
847
+ perPage?: number;
848
+ delayInMs?: number;
849
+ };
850
+ type IPaginationInfo<T extends IPaginationItem = IPaginationItem> = {
851
+ items: T[];
852
+ hasMore: boolean;
853
+ nextPage: number | undefined;
854
+ page: number;
855
+ pages: number;
856
+ perPage: number;
857
+ prevPage: number | undefined;
858
+ total: number;
859
+ };
860
+ declare function isPaginationInfo(item: unknown): item is IPaginationInfo;
861
+ declare function getPagedItems<T extends IPaginationItem = IPaginationItem>(items: T[], page: number, perPage: number): T[];
862
+ declare function getMoreItems<T extends IPaginationItem = IPaginationItem>(items: T[], page: number, perPage: number): T[];
863
+ declare function getPaginationInfo<T extends IPaginationItem = IPaginationItem>(items: T[], options?: IPaginationOptions): IPaginationInfo<T>;
864
+
865
+ declare function usePagination<T extends IPaginationItem = IPaginationItem>(items: T[], options?: {
866
+ mode?: 'pagination' | 'infinite';
867
+ page?: number;
868
+ perPage?: number;
869
+ delayInMs?: number;
870
+ }): IPaginationInfo<T> & {
871
+ loadMore: () => number;
872
+ goToPage: (page: number) => void;
873
+ goToNextPage: () => void;
874
+ goToPreviousPage: () => void;
875
+ setPerPage: (perPage: number) => void;
876
+ };
877
+
878
+ type IPaginationLegacyInfo<T = any> = {
796
879
  items: T[];
797
880
  page: number;
798
881
  pages: number;
799
882
  perPage: number;
800
883
  total: number;
801
884
  };
802
- declare function isPaginationInfo(item: unknown): item is IPaginationInfo<any>;
803
- declare function getPagedItems<T>(items: T[], page: number, perPage: number): T[];
804
- declare function getPaginationInfo<T>(items: T[], page?: number, perPage?: number): IPaginationInfo<T>;
885
+ declare function isPaginationLegacyInfo(item: unknown): item is IPaginationLegacyInfo<any>;
886
+ declare function getPagedItemsLegacy<T>(items: T[], page: number, perPage: number): T[];
887
+ declare function getPaginationLegacyInfo<T>(items: T[], page?: number, perPage?: number): IPaginationLegacyInfo<T>;
805
888
 
806
- declare function usePagination<T>($items: T[], $page?: number, $perPage?: number): {
889
+ declare function usePaginationLegacy<T>($items: T[], $page?: number, $perPage?: number): {
807
890
  items: T[];
808
891
  page: number;
809
892
  pages: number;
@@ -972,4 +1055,4 @@ type WindowSize = {
972
1055
  };
973
1056
  declare function useWindowSize(): WindowSize;
974
1057
 
975
- export { BodyScrollOptions, ClickOutGetContainer, ColorScheme, CurrentStateType, ElementStackItem, ExtraProvider, Filter, FilterMode, FilterParams, FilterValues, GeoLocationSensorState, IExtra, IFilter, IFilterOption, IGeolocationPositionError, ILabelContext, ILayoutContext, ILazyModulesContext, IPageContext, IPageRoute, IPageRouteOptions, IPaginationInfo, IParams, IParamsEncoded, IParamsQs, IUseSearchParamsEncodedResult, IUseSearchParamsQsResult, IUseSearchParamsResult, IUseSearchParamsValueResult, KeyCode, KeyMod, KeyboardOptions, KeyboardResult, LabelProvider, LabelService, LayoutProvider, LazyModulesProvider, PageProvider, SSRState, SizeResult, SizeType, Sorting, UIReducer, UIValue, UseFiltersResultType, UseKeyboard, UseKeyboardHandler, createElementWithId, createGenericContext, detectIsBrowser, filtersToParams, getCurrentPosition, getFilteredItems, getFilters, getOwnerPaddingRight, getOwnerScrollbarWidth, getPagedItems, getPaginationInfo, getPreferredColorScheme, getPreferredReducedMotion, getRealSize, getSearchParams, getSearchParamsEncoded, getSearchParamsQs, getUID, hasGeolocation, isElement, isPaginationInfo, localCollectionDelete, localCollectionFetch, localCollectionGet, localCollectionPatch, localCollectionPost, localCollectionPut, parseLabel, parseParams, pushSearchParams, pushSearchParamsEncoded, pushSearchParamsEncodedSilently, pushSearchParamsQs, pushSearchParamsQsSilently, pushSearchParamsSilently, replaceSearchParams, replaceSearchParamsEncoded, replaceSearchParamsEncodedSilently, replaceSearchParamsQs, replaceSearchParamsQsSilently, replaceSearchParamsSilently, scrollToRelativeY, scrollToSelector, scrollToY, setFilters, updateSearchParams, updateSearchParamsEncoded, updateSearchParamsQs, useApi, useApiDelete, useApiFetch, useApiGet, useApiPatch, useApiPost, useApiPut, useAutosizeTextArea, useBodyScroll, useBreakpoint, useClickAnyWhere, useClickOut, useCollectionApi, useCollectionApiDelete, useCollectionApiGet, useCollectionApiPatch, useCollectionApiPost, useCollectionApiPut, useColorScheme, useCurrency, useCurrentState, useDateTimeFormat, useDebounce, useDebounceCallback, useDebugChangedProps, useDomObserver, useDrawer, useElementSize, useEventListener, useExtra, useFilters, useFocusTrap, useGeolocation, useIdle, useInfiniteLoader, useIntersectionObserver, useIsomorphicLayoutEffect, useKeyboard, useLabel, useLayout, useLazyModules, useModal, useMounted, useNumber, usePage, usePageLoading, usePagination, usePortal, usePrevious, useRealSize, useReducedMotion, useReducedMotionLocal, useResize, useSSR, useScroll, useScrollTo, useScrolled, useSearchParams, useSearchParamsEncoded, useSearchParamsQs, useSearchParamsValue, useSorting, useSyncedRef, useUI, useUnit, useUnmountEffect, useWindowSize };
1058
+ export { BodyScrollOptions, ClickOutGetContainer, ColorScheme, CurrentStateType, ElementStackItem, ExtraProvider, Filter, FilterMode, FilterParams, FilterValues, GeoLocationSensorState, IExtra, IFilter, IFilterOption, IGeolocationPositionError, ILabelContext, ILayoutContext, ILazyModulesContext, IMetaDataContext, IPageContext, IPageRoute, IPageRouteOptions, IPaginationInfo, IPaginationItem, IPaginationLegacyInfo, IPaginationOptions, IParams, IParamsEncoded, IParamsQs, IUseSearchParamsEncodedResult, IUseSearchParamsQsResult, IUseSearchParamsResult, IUseSearchParamsValueResult, KeyCode, KeyMod, KeyboardOptions, KeyboardResult, LabelProvider, LabelService, LayoutProvider, LazyModulesProvider, MetaDataProvider, PageProvider, SSRState, SizeResult, SizeType, Sorting, UIReducer, UIValue, UseFiltersResultType, UseKeyboard, UseKeyboardHandler, createElementWithId, createGenericContext, detectIsBrowser, filtersToParams, getCurrentPosition, getFilteredItems, getFilters, getMoreItems, getOwnerPaddingRight, getOwnerScrollbarWidth, getPagedItems, getPagedItemsLegacy, getPaginationInfo, getPaginationLegacyInfo, getPreferredColorScheme, getPreferredReducedMotion, getRealSize, getSearchParams, getSearchParamsEncoded, getSearchParamsQs, getUID, hasGeolocation, isElement, isPaginationInfo, isPaginationLegacyInfo, localCollectionDelete, localCollectionFetch, localCollectionGet, localCollectionPatch, localCollectionPost, localCollectionPut, parseLabel, parseParams, pushSearchParams, pushSearchParamsEncoded, pushSearchParamsEncodedSilently, pushSearchParamsQs, pushSearchParamsQsSilently, pushSearchParamsSilently, replaceSearchParams, replaceSearchParamsEncoded, replaceSearchParamsEncodedSilently, replaceSearchParamsQs, replaceSearchParamsQsSilently, replaceSearchParamsSilently, scrollToRelativeY, scrollToSelector, scrollToY, setFilters, updateSearchParams, updateSearchParamsEncoded, updateSearchParamsQs, useApi, useApiDelete, useApiFetch, useApiGet, useApiPatch, useApiPost, useApiPut, useAutosizeTextArea, useBodyScroll, useBreakpoint, useClickAnyWhere, useClickOut, useCollectionApi, useCollectionApiDelete, useCollectionApiGet, useCollectionApiPatch, useCollectionApiPost, useCollectionApiPut, useColorScheme, useCurrency, useCurrentState, useDateTimeFormat, useDebounce, useDebounceCallback, useDebugChangedProps, useDomObserver, useDrawer, useElementSize, useEventListener, useExtra, useFilters, useFocusTrap, useGeolocation, useIdle, useInfiniteLoader, useIntersectionObserver, useIsomorphicLayoutEffect, useKeyboard, useLabel, useLayout, useLazyModules, useMetaData, useModal, useMounted, useNumber, usePage, usePageLoading, usePagination, usePaginationLegacy, usePortal, usePrevious, useRealSize, useReducedMotion, useReducedMotionLocal, useResize, useSSR, useScroll, useScrollTo, useScrolled, useSearchParams, useSearchParamsEncoded, useSearchParamsQs, useSearchParamsValue, useSorting, useSyncedRef, useUI, useUnit, useUnmountEffect, useWindowSize };