@websolutespa/bom-mixer-hooks 0.2.2 → 1.1.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 +12 -0
- package/dist/index.d.ts +31 -27
- package/dist/index.js +62 -40
- package/dist/index.mjs +41 -20
- package/package.json +2 -2
- package/src/index.ts +2 -1
- package/src/useApi/useApi.test.tsx +11 -9
- package/src/useApi/useApi.ts +25 -24
- package/src/useCart/useCart.tsx +2 -5
- package/src/useCheckout/useCheckout.tsx +3 -6
- package/src/useCurrency/useCurrency.test.tsx +2 -1
- package/src/useCurrency/useCurrency.ts +1 -1
- package/src/useDateTimeFormat/useDateTimeFormat.test.tsx +2 -1
- package/src/useHttp/useHttp.test.tsx +8 -9
- package/src/useHttp/useHttp.ts +11 -11
- package/src/useLabel/useLabel.test.tsx +2 -1
- package/src/useLayout/useLayout.test.tsx +2 -1
- package/src/useLayout/useLayout.tsx +1 -1
- package/src/useNumber/useNumber.test.tsx +2 -1
- package/src/usePage/usePage.tsx +1 -1
- package/src/useScroll/useScroll.test.tsx +1 -1
- package/src/useScroll/useScroll.ts +2 -2
- package/src/useScrollTo/useScrollTo.test.tsx +4 -4
- package/src/useScrollTo/useScrollTo.ts +2 -2
- package/src/useScrolled/useScrolled.test.tsx +34 -0
- package/src/useScrolled/useScrolled.ts +28 -0
- package/src/useUnit/useUnit.test.tsx +2 -1
package/CHANGELOG.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
import * as React$1 from 'react';
|
|
2
2
|
import React__default, { RefObject, Dispatch, SetStateAction, MutableRefObject, ComponentProps, useEffect } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { ApiRequestOptions } from '@websolutespa/bom-mixer-store';
|
|
4
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
5
|
import * as zustand_middleware from 'zustand/middleware';
|
|
5
6
|
import { StateStorage } from 'zustand/middleware';
|
|
6
7
|
import * as zustand from 'zustand';
|
|
8
|
+
import { ISchema, IEquatable, ILayout, IPage } from '@websolutespa/bom-core';
|
|
7
9
|
import { ICartItem, ICartAddItem, IAddressOptions, ICheckoutPartial, IFeatureType, IUser } from '@websolutespa/bom-mixer-models';
|
|
8
10
|
import { NextRouter } from 'next/router';
|
|
9
11
|
|
|
10
|
-
declare function useApiFetch<T =
|
|
11
|
-
declare function useApiGet<T =
|
|
12
|
-
declare function useApiPost<T =
|
|
13
|
-
declare function useApiPut<T =
|
|
14
|
-
declare function useApiPatch<T =
|
|
15
|
-
declare function useApiDelete<T =
|
|
12
|
+
declare function useApiFetch<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any, React$1.Dispatch<any>];
|
|
13
|
+
declare function useApiGet<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any, React$1.Dispatch<any>];
|
|
14
|
+
declare function useApiPost<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any, React$1.Dispatch<any>];
|
|
15
|
+
declare function useApiPut<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any, React$1.Dispatch<any>];
|
|
16
|
+
declare function useApiPatch<T = unknown>(pathname: string, payload: unknown, options?: ApiRequestOptions): [T | undefined, boolean, any, React$1.Dispatch<any>];
|
|
17
|
+
declare function useApiDelete<T = unknown>(pathname: string, options?: ApiRequestOptions): [T | undefined, boolean, any, React$1.Dispatch<any>];
|
|
16
18
|
type Api = {
|
|
17
|
-
get: <T =
|
|
18
|
-
post: <T =
|
|
19
|
-
put: <T =
|
|
20
|
-
patch: <T =
|
|
21
|
-
delete: <T =
|
|
19
|
+
get: <T = unknown>(pathname: string, options?: ApiRequestOptions) => Promise<T>;
|
|
20
|
+
post: <T = unknown>(pathname: string, payload?: unknown, options?: ApiRequestOptions) => Promise<T>;
|
|
21
|
+
put: <T = unknown>(pathname: string, payload?: unknown, options?: ApiRequestOptions) => Promise<T>;
|
|
22
|
+
patch: <T = unknown>(pathname: string, payload?: unknown, options?: ApiRequestOptions) => Promise<T>;
|
|
23
|
+
delete: <T = unknown>(pathname: string, options?: ApiRequestOptions) => Promise<T>;
|
|
22
24
|
};
|
|
23
25
|
declare function useApi(): Api;
|
|
24
26
|
|
|
@@ -73,8 +75,8 @@ type CartProviderProps = React.PropsWithChildren<{
|
|
|
73
75
|
items?: ICartItem[];
|
|
74
76
|
storage?: StateStorage;
|
|
75
77
|
}>;
|
|
76
|
-
declare function CartProvider({ children, ...props }: CartProviderProps): JSX.Element;
|
|
77
|
-
declare function useCart<T>(selector: (state: CartState) => T
|
|
78
|
+
declare function CartProvider({ children, ...props }: CartProviderProps): react_jsx_runtime.JSX.Element;
|
|
79
|
+
declare function useCart<T>(selector: (state: CartState) => T): T;
|
|
78
80
|
|
|
79
81
|
type CheckoutProps = {
|
|
80
82
|
hydrated: boolean;
|
|
@@ -103,8 +105,8 @@ type CheckoutProviderProps = React.PropsWithChildren<{
|
|
|
103
105
|
checkout?: ICheckoutPartial;
|
|
104
106
|
storage?: StateStorage;
|
|
105
107
|
}>;
|
|
106
|
-
declare function CheckoutProvider({ children, ...props }: CheckoutProviderProps): JSX.Element;
|
|
107
|
-
declare function useCheckout<T>(selector: (state: CheckoutState) => T
|
|
108
|
+
declare function CheckoutProvider({ children, ...props }: CheckoutProviderProps): react_jsx_runtime.JSX.Element;
|
|
109
|
+
declare function useCheckout<T>(selector: (state: CheckoutState) => T): T;
|
|
108
110
|
|
|
109
111
|
declare function useClickAnyWhere(handler: (event: MouseEvent) => void): void;
|
|
110
112
|
|
|
@@ -375,7 +377,7 @@ type ILabelContext = (key: string, params?: {
|
|
|
375
377
|
declare const useLabel: () => ILabelContext;
|
|
376
378
|
declare function LabelProvider({ children }: {
|
|
377
379
|
children?: React__default.ReactNode;
|
|
378
|
-
}): JSX.Element;
|
|
380
|
+
}): react_jsx_runtime.JSX.Element;
|
|
379
381
|
declare function parseParams(label: string, params: {
|
|
380
382
|
[key: string]: any;
|
|
381
383
|
}): string;
|
|
@@ -385,7 +387,7 @@ declare const useLayout: () => ILayout;
|
|
|
385
387
|
declare function LayoutProvider({ children, layout }: {
|
|
386
388
|
children?: React__default.ReactNode;
|
|
387
389
|
layout: ILayout;
|
|
388
|
-
}): JSX.Element;
|
|
390
|
+
}): react_jsx_runtime.JSX.Element;
|
|
389
391
|
|
|
390
392
|
declare function useModal(): [modal: UIValue, open: (value?: string) => void, close: () => void];
|
|
391
393
|
|
|
@@ -398,7 +400,7 @@ declare const usePage: () => NonNullable<IPage>;
|
|
|
398
400
|
declare function PageProvider({ children, page }: {
|
|
399
401
|
children?: React__default.ReactNode;
|
|
400
402
|
page: IPage;
|
|
401
|
-
}): JSX.Element;
|
|
403
|
+
}): react_jsx_runtime.JSX.Element;
|
|
402
404
|
|
|
403
405
|
type IPaginationInfo<T> = {
|
|
404
406
|
items: T[];
|
|
@@ -436,6 +438,13 @@ declare function getRealSize(element: HTMLElement | null): SizeType;
|
|
|
436
438
|
|
|
437
439
|
declare function useResize(callback: () => unknown, immediate?: boolean): void;
|
|
438
440
|
|
|
441
|
+
type SSRState = {
|
|
442
|
+
isBrowser: boolean;
|
|
443
|
+
isServer: boolean;
|
|
444
|
+
};
|
|
445
|
+
declare const detectIsBrowser: () => boolean;
|
|
446
|
+
declare function useSSR(): SSRState;
|
|
447
|
+
|
|
439
448
|
type Scroll = {
|
|
440
449
|
left: number;
|
|
441
450
|
top: number;
|
|
@@ -447,6 +456,8 @@ declare function scrollToSelector(selector?: string, offset?: number): void;
|
|
|
447
456
|
declare function scrollToRelativeY(y?: number, offset?: number): void;
|
|
448
457
|
declare function scrollToY(y?: number): void;
|
|
449
458
|
|
|
459
|
+
declare function useScrolled(callback?: (top: number, left: number) => boolean): boolean;
|
|
460
|
+
|
|
450
461
|
declare const isBrowser: boolean;
|
|
451
462
|
declare function getSearchParams(url: string, key?: string): IParams | string | null;
|
|
452
463
|
declare function updateSearchParams(currentPath: string, params: IParams): {
|
|
@@ -504,13 +515,6 @@ declare function useSorting<T>(items_: T[], callback_: (items: T[], sort?: IEqua
|
|
|
504
515
|
setSort: (sort?: IEquatable) => void;
|
|
505
516
|
};
|
|
506
517
|
|
|
507
|
-
type SSRState = {
|
|
508
|
-
isBrowser: boolean;
|
|
509
|
-
isServer: boolean;
|
|
510
|
-
};
|
|
511
|
-
declare const detectIsBrowser: () => boolean;
|
|
512
|
-
declare function useSSR(): SSRState;
|
|
513
|
-
|
|
514
518
|
declare function useSwiperIndex(): [number, (index: number) => void];
|
|
515
519
|
|
|
516
520
|
/**
|
|
@@ -548,4 +552,4 @@ type WindowSize = {
|
|
|
548
552
|
};
|
|
549
553
|
declare function useWindowSize(): WindowSize;
|
|
550
554
|
|
|
551
|
-
export { BodyScrollOptions, CartContext, CartProvider, CheckoutContext, CheckoutProvider, ClickOutGetContainer, CurrentStateType, ElementStackItem, Filter, FilterMode, FilterParams, FilterValues, GeoLocationSensorState, IFilter, IFilterOption, IGeolocationPositionError, ILabelContext, ILayoutContext, IPageContext, IPaginationInfo, IParams, IParamsEncoded, IUseSearchParamsEncodedResult, IUseSearchParamsResult, IUseSearchParamsValueResult, KeyCode, KeyMod, KeyboardOptions, KeyboardResult, LabelProvider, LayoutProvider, PageProvider, SSRState, SizeResult, SizeType, Sorting, UIReducer, UIValue, UseFiltersResultType, UseKeyboard, UseKeyboardHandler, createElementWithId, createGenericContext, decode, detectIsBrowser, filtersToParams, getCurrentPosition, getFilteredItems, getFilters, getOwnerPaddingRight, getOwnerScrollbarWidth, getPagedItems, getRealSize, getSearchParams, getSearchParamsEncoded, getUID, hasGeolocation, isBrowser, parseParams, pushSearchParams, pushSearchParamsEncoded, replaceSearchParams, replaceSearchParamsEncoded, replaceSearchParamsEncodedSilently, replaceSearchParamsSilently, scrollToRelativeY, scrollToSelector, scrollToY, setFilters, updateSearchParams, updateSearchParamsEncoded, useApi, useApiDelete, useApiFetch, useApiGet, useApiPatch, useApiPost, useApiPut, useBodyScroll, useBreakpoint, useCart, useCheckout, useClickAnyWhere, useClickOut, useCurrency, useCurrentState, useDateTimeFormat, useDebounce, useDebounceCallback, useDebugChangedProps, useDomObserver, useDrawer, useElementSize, useEventListener, useFilters, useGeolocation, useIdle, useInfiniteLoader, useIsomorphicLayoutEffect, useKeyboard, useLabel, useLayout, useModal, useMounted, useNumber, usePage, usePagination, usePortal, usePrevious, useRealSize, useResize, useSSR, useScroll, useScrollTo, useSearchParams, useSearchParamsEncoded, useSearchParamsValue, useSorting, useSwiperIndex, useSyncedRef, useUI, useUnit, useUnmountEffect, useUser, useWindowSize };
|
|
555
|
+
export { BodyScrollOptions, CartContext, CartProvider, CheckoutContext, CheckoutProvider, ClickOutGetContainer, CurrentStateType, ElementStackItem, Filter, FilterMode, FilterParams, FilterValues, GeoLocationSensorState, IFilter, IFilterOption, IGeolocationPositionError, ILabelContext, ILayoutContext, IPageContext, IPaginationInfo, IParams, IParamsEncoded, IUseSearchParamsEncodedResult, IUseSearchParamsResult, IUseSearchParamsValueResult, KeyCode, KeyMod, KeyboardOptions, KeyboardResult, LabelProvider, LayoutProvider, PageProvider, SSRState, SizeResult, SizeType, Sorting, UIReducer, UIValue, UseFiltersResultType, UseKeyboard, UseKeyboardHandler, createElementWithId, createGenericContext, decode, detectIsBrowser, filtersToParams, getCurrentPosition, getFilteredItems, getFilters, getOwnerPaddingRight, getOwnerScrollbarWidth, getPagedItems, getRealSize, getSearchParams, getSearchParamsEncoded, getUID, hasGeolocation, isBrowser, parseParams, pushSearchParams, pushSearchParamsEncoded, replaceSearchParams, replaceSearchParamsEncoded, replaceSearchParamsEncodedSilently, replaceSearchParamsSilently, scrollToRelativeY, scrollToSelector, scrollToY, setFilters, updateSearchParams, updateSearchParamsEncoded, useApi, useApiDelete, useApiFetch, useApiGet, useApiPatch, useApiPost, useApiPut, useBodyScroll, useBreakpoint, useCart, useCheckout, useClickAnyWhere, useClickOut, useCurrency, useCurrentState, useDateTimeFormat, useDebounce, useDebounceCallback, useDebugChangedProps, useDomObserver, useDrawer, useElementSize, useEventListener, useFilters, useGeolocation, useIdle, useInfiniteLoader, useIsomorphicLayoutEffect, useKeyboard, useLabel, useLayout, useModal, useMounted, useNumber, usePage, usePagination, usePortal, usePrevious, useRealSize, useResize, useSSR, useScroll, useScrollTo, useScrolled, useSearchParams, useSearchParamsEncoded, useSearchParamsValue, useSorting, useSwiperIndex, useSyncedRef, useUI, useUnit, useUnmountEffect, useUser, useWindowSize };
|
package/dist/index.js
CHANGED
|
@@ -153,6 +153,7 @@ __export(src_exports, {
|
|
|
153
153
|
useSSR: () => useSSR,
|
|
154
154
|
useScroll: () => useScroll,
|
|
155
155
|
useScrollTo: () => useScrollTo,
|
|
156
|
+
useScrolled: () => useScrolled,
|
|
156
157
|
useSearchParams: () => useSearchParams,
|
|
157
158
|
useSearchParamsEncoded: () => useSearchParamsEncoded,
|
|
158
159
|
useSearchParamsValue: () => useSearchParamsValue,
|
|
@@ -218,7 +219,7 @@ function LayoutProvider({ children, layout }) {
|
|
|
218
219
|
// src/useApi/useApi.ts
|
|
219
220
|
function useApiFetch(pathname, options = {}) {
|
|
220
221
|
const layout = useLayout();
|
|
221
|
-
return useHttpFetch(pathname, options, import_bom_mixer_store.
|
|
222
|
+
return useHttpFetch(pathname, options, import_bom_mixer_store.localApiFetch, layout);
|
|
222
223
|
}
|
|
223
224
|
function useApiGet(pathname, options = {}) {
|
|
224
225
|
return useApiFetch(pathname, __spreadProps(__spreadValues({}, options), { method: "GET" }));
|
|
@@ -239,19 +240,19 @@ function useApi() {
|
|
|
239
240
|
const layout = useLayout();
|
|
240
241
|
return {
|
|
241
242
|
get: (_0, ..._1) => __async(this, [_0, ..._1], function* (pathname, options = {}) {
|
|
242
|
-
return (0, import_bom_mixer_store.
|
|
243
|
+
return (0, import_bom_mixer_store.localApiGet)(pathname, options, layout);
|
|
243
244
|
}),
|
|
244
245
|
post: (_0, _1, ..._2) => __async(this, [_0, _1, ..._2], function* (pathname, payload, options = {}) {
|
|
245
|
-
return (0, import_bom_mixer_store.
|
|
246
|
+
return (0, import_bom_mixer_store.localApiPost)(pathname, payload, options, layout);
|
|
246
247
|
}),
|
|
247
248
|
put: (_0, _1, ..._2) => __async(this, [_0, _1, ..._2], function* (pathname, payload, options = {}) {
|
|
248
|
-
return (0, import_bom_mixer_store.
|
|
249
|
+
return (0, import_bom_mixer_store.localApiPut)(pathname, payload, options, layout);
|
|
249
250
|
}),
|
|
250
251
|
patch: (_0, _1, ..._2) => __async(this, [_0, _1, ..._2], function* (pathname, payload, options = {}) {
|
|
251
|
-
return (0, import_bom_mixer_store.
|
|
252
|
+
return (0, import_bom_mixer_store.localApiPatch)(pathname, payload, options, layout);
|
|
252
253
|
}),
|
|
253
254
|
delete: (_0, ..._1) => __async(this, [_0, ..._1], function* (pathname, options = {}) {
|
|
254
|
-
return (0, import_bom_mixer_store.
|
|
255
|
+
return (0, import_bom_mixer_store.localApiDelete)(pathname, options, layout);
|
|
255
256
|
})
|
|
256
257
|
};
|
|
257
258
|
}
|
|
@@ -488,11 +489,11 @@ function CartProvider(_a) {
|
|
|
488
489
|
}
|
|
489
490
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CartContext.Provider, { value: storeRef.current, children });
|
|
490
491
|
}
|
|
491
|
-
function useCart(selector
|
|
492
|
+
function useCart(selector) {
|
|
492
493
|
const store = (0, import_react8.useContext)(CartContext);
|
|
493
494
|
if (!store)
|
|
494
495
|
throw new Error("Missing CartContext.Provider in the tree");
|
|
495
|
-
return (0, import_zustand.useStore)(store, selector
|
|
496
|
+
return (0, import_zustand.useStore)(store, selector);
|
|
496
497
|
}
|
|
497
498
|
|
|
498
499
|
// src/useCheckout/useCheckout.tsx
|
|
@@ -548,11 +549,11 @@ function CheckoutProvider(_a) {
|
|
|
548
549
|
}
|
|
549
550
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CheckoutContext.Provider, { value: storeRef.current, children });
|
|
550
551
|
}
|
|
551
|
-
function useCheckout(selector
|
|
552
|
+
function useCheckout(selector) {
|
|
552
553
|
const store = (0, import_react9.useContext)(CheckoutContext);
|
|
553
554
|
if (!store)
|
|
554
555
|
throw new Error("Missing CheckoutContext.Provider in the tree");
|
|
555
|
-
return (0, import_zustand2.useStore)(store, selector
|
|
556
|
+
return (0, import_zustand2.useStore)(store, selector);
|
|
556
557
|
}
|
|
557
558
|
|
|
558
559
|
// src/useClickAnyWhere/useClickAnyWhere.ts
|
|
@@ -1523,8 +1524,8 @@ var import_react30 = require("react");
|
|
|
1523
1524
|
function useScroll() {
|
|
1524
1525
|
const [scroll, setScroll] = (0, import_react30.useState)({ left: 0, top: 0 });
|
|
1525
1526
|
const onScroll = () => {
|
|
1526
|
-
const left = window.
|
|
1527
|
-
const top = window.
|
|
1527
|
+
const left = window.scrollX;
|
|
1528
|
+
const top = window.scrollY;
|
|
1528
1529
|
if (scroll.left !== left || scroll.top !== top) {
|
|
1529
1530
|
setScroll({ left, top });
|
|
1530
1531
|
}
|
|
@@ -1558,11 +1559,11 @@ function scrollToSelector(selector, offset = 0) {
|
|
|
1558
1559
|
}
|
|
1559
1560
|
}
|
|
1560
1561
|
function scrollToRelativeY(y = 0, offset = 0) {
|
|
1561
|
-
const to = window.
|
|
1562
|
+
const to = window.scrollY + y - 60 + offset;
|
|
1562
1563
|
return scrollToY(to);
|
|
1563
1564
|
}
|
|
1564
1565
|
function scrollToY(y = 0) {
|
|
1565
|
-
const from = window.
|
|
1566
|
+
const from = window.scrollY;
|
|
1566
1567
|
const to = y;
|
|
1567
1568
|
const duration = Math.sqrt(Math.abs(to - from) / 4e3);
|
|
1568
1569
|
(0, import_framer_motion.animate)(from, to, {
|
|
@@ -1571,9 +1572,29 @@ function scrollToY(y = 0) {
|
|
|
1571
1572
|
});
|
|
1572
1573
|
}
|
|
1573
1574
|
|
|
1575
|
+
// src/useScrolled/useScrolled.ts
|
|
1576
|
+
var import_react31 = require("react");
|
|
1577
|
+
var DEFAULT_CALLBACK = (top, left) => {
|
|
1578
|
+
return top > 0;
|
|
1579
|
+
};
|
|
1580
|
+
function useScrolled(callback = DEFAULT_CALLBACK) {
|
|
1581
|
+
const [scrolled, setScrolled] = (0, import_react31.useState)(false);
|
|
1582
|
+
const onScrolled = () => {
|
|
1583
|
+
const scrolled_ = callback(window.scrollY, window.scrollX);
|
|
1584
|
+
if (scrolled !== scrolled_) {
|
|
1585
|
+
setScrolled(scrolled_);
|
|
1586
|
+
}
|
|
1587
|
+
};
|
|
1588
|
+
useEventListener("scroll", onScrolled);
|
|
1589
|
+
useIsomorphicLayoutEffect(() => {
|
|
1590
|
+
onScrolled();
|
|
1591
|
+
}, []);
|
|
1592
|
+
return scrolled;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1574
1595
|
// src/useSearchParams/useSearchParams.ts
|
|
1575
1596
|
var import_router = require("next/router");
|
|
1576
|
-
var
|
|
1597
|
+
var import_react32 = require("react");
|
|
1577
1598
|
var isBrowser = typeof window !== "undefined";
|
|
1578
1599
|
function replace_(params) {
|
|
1579
1600
|
if (window.history) {
|
|
@@ -1632,29 +1653,29 @@ function replaceSearchParamsSilently(params) {
|
|
|
1632
1653
|
}
|
|
1633
1654
|
function useSearchParams() {
|
|
1634
1655
|
const router = (0, import_router.useRouter)();
|
|
1635
|
-
const initialValue = (0,
|
|
1656
|
+
const initialValue = (0, import_react32.useMemo)(() => {
|
|
1636
1657
|
const params2 = deserialize_(router.asPath);
|
|
1637
1658
|
const value = Object.fromEntries(params2);
|
|
1638
1659
|
return value;
|
|
1639
1660
|
}, [router.asPath]);
|
|
1640
1661
|
const params = initialValue;
|
|
1641
|
-
const replaceParamsSilently = (0,
|
|
1662
|
+
const replaceParamsSilently = (0, import_react32.useCallback)((params2) => {
|
|
1642
1663
|
replaceSearchParamsSilently(params2);
|
|
1643
1664
|
}, []);
|
|
1644
|
-
const replaceParams = (0,
|
|
1665
|
+
const replaceParams = (0, import_react32.useCallback)((params2) => {
|
|
1645
1666
|
replaceSearchParams(router, params2);
|
|
1646
1667
|
}, [router]);
|
|
1647
1668
|
return { params, replaceParamsSilently, replaceParams };
|
|
1648
1669
|
}
|
|
1649
1670
|
function useSearchParamsValue(key) {
|
|
1650
1671
|
const router = (0, import_router.useRouter)();
|
|
1651
|
-
const initialValue = (0,
|
|
1672
|
+
const initialValue = (0, import_react32.useMemo)(() => {
|
|
1652
1673
|
const params2 = deserialize_(router.asPath);
|
|
1653
1674
|
const value = params2.get(key);
|
|
1654
1675
|
return value;
|
|
1655
1676
|
}, [key, router.asPath]);
|
|
1656
1677
|
const params = initialValue;
|
|
1657
|
-
const replaceParamsSilently = (0,
|
|
1678
|
+
const replaceParamsSilently = (0, import_react32.useCallback)((params2) => {
|
|
1658
1679
|
replaceSearchParamsSilently(params2);
|
|
1659
1680
|
}, []);
|
|
1660
1681
|
return { params, replaceParamsSilently };
|
|
@@ -1662,7 +1683,7 @@ function useSearchParamsValue(key) {
|
|
|
1662
1683
|
|
|
1663
1684
|
// src/useSearchParamsEncoded/useSearchParamsEncoded.ts
|
|
1664
1685
|
var import_router2 = require("next/router");
|
|
1665
|
-
var
|
|
1686
|
+
var import_react33 = require("react");
|
|
1666
1687
|
var USE_ENCRYPTION = true;
|
|
1667
1688
|
function base64ToString(base64) {
|
|
1668
1689
|
if (!USE_ENCRYPTION)
|
|
@@ -1768,27 +1789,27 @@ function replaceSearchParamsEncodedSilently(value, key) {
|
|
|
1768
1789
|
}
|
|
1769
1790
|
function useSearchParamsEncoded(key) {
|
|
1770
1791
|
const router = (0, import_router2.useRouter)();
|
|
1771
|
-
const initialValue = (0,
|
|
1792
|
+
const initialValue = (0, import_react33.useMemo)(() => {
|
|
1772
1793
|
const value = getSearchParamsEncoded(router.asPath, key);
|
|
1773
1794
|
return value;
|
|
1774
1795
|
}, [key, router.asPath]);
|
|
1775
1796
|
const params = initialValue;
|
|
1776
|
-
const replaceParamsSilently = (0,
|
|
1797
|
+
const replaceParamsSilently = (0, import_react33.useCallback)((params2) => {
|
|
1777
1798
|
replaceSearchParamsEncodedSilently(params2, key);
|
|
1778
1799
|
}, [key]);
|
|
1779
|
-
const replaceParams = (0,
|
|
1800
|
+
const replaceParams = (0, import_react33.useCallback)((params2) => {
|
|
1780
1801
|
replaceSearchParamsEncoded(router, params2, key);
|
|
1781
1802
|
}, [key, router]);
|
|
1782
1803
|
return { params, replaceParamsSilently, replaceParams };
|
|
1783
1804
|
}
|
|
1784
1805
|
|
|
1785
1806
|
// src/useSorting/useSorting.ts
|
|
1786
|
-
var
|
|
1807
|
+
var import_react34 = require("react");
|
|
1787
1808
|
function useSorting(items_, callback_, sort_) {
|
|
1788
|
-
const [sort, setSort] = (0,
|
|
1789
|
-
const [items, setItems] = (0,
|
|
1790
|
-
const isInitialMount = (0,
|
|
1791
|
-
(0,
|
|
1809
|
+
const [sort, setSort] = (0, import_react34.useState)(sort_);
|
|
1810
|
+
const [items, setItems] = (0, import_react34.useState)(callback_(items_.slice(), sort));
|
|
1811
|
+
const isInitialMount = (0, import_react34.useRef)(true);
|
|
1812
|
+
(0, import_react34.useEffect)(() => {
|
|
1792
1813
|
if (isInitialMount.current) {
|
|
1793
1814
|
isInitialMount.current = false;
|
|
1794
1815
|
} else {
|
|
@@ -1804,18 +1825,18 @@ function useSorting(items_, callback_, sort_) {
|
|
|
1804
1825
|
}
|
|
1805
1826
|
|
|
1806
1827
|
// src/useSwiperIndex/useSwiperIndex.ts
|
|
1807
|
-
var
|
|
1808
|
-
var
|
|
1828
|
+
var import_react35 = require("react");
|
|
1829
|
+
var import_react36 = require("swiper/react");
|
|
1809
1830
|
function useSwiperIndex() {
|
|
1810
|
-
const swiper = (0,
|
|
1811
|
-
const [index, setIndex] = (0,
|
|
1812
|
-
const slideTo = (0,
|
|
1831
|
+
const swiper = (0, import_react36.useSwiper)();
|
|
1832
|
+
const [index, setIndex] = (0, import_react35.useState)(swiper.realIndex);
|
|
1833
|
+
const slideTo = (0, import_react35.useCallback)((index2) => {
|
|
1813
1834
|
swiper.slideTo(index2);
|
|
1814
1835
|
}, [swiper]);
|
|
1815
1836
|
const onSlideChange = (swiper2) => {
|
|
1816
1837
|
setIndex(swiper2.realIndex);
|
|
1817
1838
|
};
|
|
1818
|
-
(0,
|
|
1839
|
+
(0, import_react35.useEffect)(() => {
|
|
1819
1840
|
if (swiper) {
|
|
1820
1841
|
swiper.on("slideChange", onSlideChange);
|
|
1821
1842
|
}
|
|
@@ -1829,11 +1850,11 @@ function useSwiperIndex() {
|
|
|
1829
1850
|
}
|
|
1830
1851
|
|
|
1831
1852
|
// src/useSyncedRef/useSyncedRef.ts
|
|
1832
|
-
var
|
|
1853
|
+
var import_react37 = require("react");
|
|
1833
1854
|
function useSyncedRef(value) {
|
|
1834
|
-
const ref = (0,
|
|
1855
|
+
const ref = (0, import_react37.useRef)(value);
|
|
1835
1856
|
ref.current = value;
|
|
1836
|
-
return (0,
|
|
1857
|
+
return (0, import_react37.useMemo)(() => Object.freeze({
|
|
1837
1858
|
get current() {
|
|
1838
1859
|
return ref.current;
|
|
1839
1860
|
}
|
|
@@ -1846,10 +1867,10 @@ function useUnit(unit = "kilometer", locale) {
|
|
|
1846
1867
|
}
|
|
1847
1868
|
|
|
1848
1869
|
// src/useUnmountEffect/useUnmountEffect.ts
|
|
1849
|
-
var
|
|
1870
|
+
var import_react38 = require("react");
|
|
1850
1871
|
function useUnmountEffect(effect) {
|
|
1851
1872
|
const effectRef = useSyncedRef(effect);
|
|
1852
|
-
(0,
|
|
1873
|
+
(0, import_react38.useEffect)(() => () => {
|
|
1853
1874
|
effectRef.current();
|
|
1854
1875
|
}, []);
|
|
1855
1876
|
}
|
|
@@ -1947,6 +1968,7 @@ var useUser = (0, import_zustand4.create)((set) => ({
|
|
|
1947
1968
|
useSSR,
|
|
1948
1969
|
useScroll,
|
|
1949
1970
|
useScrollTo,
|
|
1971
|
+
useScrolled,
|
|
1950
1972
|
useSearchParams,
|
|
1951
1973
|
useSearchParamsEncoded,
|
|
1952
1974
|
useSearchParamsValue,
|
package/dist/index.mjs
CHANGED
|
@@ -51,7 +51,7 @@ var __async = (__this, __arguments, generator) => {
|
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
// src/useApi/useApi.ts
|
|
54
|
-
import {
|
|
54
|
+
import { localApiDelete, localApiFetch, localApiGet, localApiPatch, localApiPost, localApiPut } from "@websolutespa/bom-mixer-store";
|
|
55
55
|
|
|
56
56
|
// src/useHttp/useHttp.ts
|
|
57
57
|
import { httpFetch } from "@websolutespa/bom-core";
|
|
@@ -101,7 +101,7 @@ function LayoutProvider({ children, layout }) {
|
|
|
101
101
|
// src/useApi/useApi.ts
|
|
102
102
|
function useApiFetch(pathname, options = {}) {
|
|
103
103
|
const layout = useLayout();
|
|
104
|
-
return useHttpFetch(pathname, options,
|
|
104
|
+
return useHttpFetch(pathname, options, localApiFetch, layout);
|
|
105
105
|
}
|
|
106
106
|
function useApiGet(pathname, options = {}) {
|
|
107
107
|
return useApiFetch(pathname, __spreadProps(__spreadValues({}, options), { method: "GET" }));
|
|
@@ -122,19 +122,19 @@ function useApi() {
|
|
|
122
122
|
const layout = useLayout();
|
|
123
123
|
return {
|
|
124
124
|
get: (_0, ..._1) => __async(this, [_0, ..._1], function* (pathname, options = {}) {
|
|
125
|
-
return
|
|
125
|
+
return localApiGet(pathname, options, layout);
|
|
126
126
|
}),
|
|
127
127
|
post: (_0, _1, ..._2) => __async(this, [_0, _1, ..._2], function* (pathname, payload, options = {}) {
|
|
128
|
-
return
|
|
128
|
+
return localApiPost(pathname, payload, options, layout);
|
|
129
129
|
}),
|
|
130
130
|
put: (_0, _1, ..._2) => __async(this, [_0, _1, ..._2], function* (pathname, payload, options = {}) {
|
|
131
|
-
return
|
|
131
|
+
return localApiPut(pathname, payload, options, layout);
|
|
132
132
|
}),
|
|
133
133
|
patch: (_0, _1, ..._2) => __async(this, [_0, _1, ..._2], function* (pathname, payload, options = {}) {
|
|
134
|
-
return
|
|
134
|
+
return localApiPatch(pathname, payload, options, layout);
|
|
135
135
|
}),
|
|
136
136
|
delete: (_0, ..._1) => __async(this, [_0, ..._1], function* (pathname, options = {}) {
|
|
137
|
-
return
|
|
137
|
+
return localApiDelete(pathname, options, layout);
|
|
138
138
|
})
|
|
139
139
|
};
|
|
140
140
|
}
|
|
@@ -371,11 +371,11 @@ function CartProvider(_a) {
|
|
|
371
371
|
}
|
|
372
372
|
return /* @__PURE__ */ jsx2(CartContext.Provider, { value: storeRef.current, children });
|
|
373
373
|
}
|
|
374
|
-
function useCart(selector
|
|
374
|
+
function useCart(selector) {
|
|
375
375
|
const store = useContext3(CartContext);
|
|
376
376
|
if (!store)
|
|
377
377
|
throw new Error("Missing CartContext.Provider in the tree");
|
|
378
|
-
return useStore(store, selector
|
|
378
|
+
return useStore(store, selector);
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
// src/useCheckout/useCheckout.tsx
|
|
@@ -431,11 +431,11 @@ function CheckoutProvider(_a) {
|
|
|
431
431
|
}
|
|
432
432
|
return /* @__PURE__ */ jsx3(CheckoutContext.Provider, { value: storeRef.current, children });
|
|
433
433
|
}
|
|
434
|
-
function useCheckout(selector
|
|
434
|
+
function useCheckout(selector) {
|
|
435
435
|
const store = useContext4(CheckoutContext);
|
|
436
436
|
if (!store)
|
|
437
437
|
throw new Error("Missing CheckoutContext.Provider in the tree");
|
|
438
|
-
return useStore2(store, selector
|
|
438
|
+
return useStore2(store, selector);
|
|
439
439
|
}
|
|
440
440
|
|
|
441
441
|
// src/useClickAnyWhere/useClickAnyWhere.ts
|
|
@@ -1406,8 +1406,8 @@ import { useState as useState16 } from "react";
|
|
|
1406
1406
|
function useScroll() {
|
|
1407
1407
|
const [scroll, setScroll] = useState16({ left: 0, top: 0 });
|
|
1408
1408
|
const onScroll = () => {
|
|
1409
|
-
const left = window.
|
|
1410
|
-
const top = window.
|
|
1409
|
+
const left = window.scrollX;
|
|
1410
|
+
const top = window.scrollY;
|
|
1411
1411
|
if (scroll.left !== left || scroll.top !== top) {
|
|
1412
1412
|
setScroll({ left, top });
|
|
1413
1413
|
}
|
|
@@ -1441,11 +1441,11 @@ function scrollToSelector(selector, offset = 0) {
|
|
|
1441
1441
|
}
|
|
1442
1442
|
}
|
|
1443
1443
|
function scrollToRelativeY(y = 0, offset = 0) {
|
|
1444
|
-
const to = window.
|
|
1444
|
+
const to = window.scrollY + y - 60 + offset;
|
|
1445
1445
|
return scrollToY(to);
|
|
1446
1446
|
}
|
|
1447
1447
|
function scrollToY(y = 0) {
|
|
1448
|
-
const from = window.
|
|
1448
|
+
const from = window.scrollY;
|
|
1449
1449
|
const to = y;
|
|
1450
1450
|
const duration = Math.sqrt(Math.abs(to - from) / 4e3);
|
|
1451
1451
|
animate(from, to, {
|
|
@@ -1454,6 +1454,26 @@ function scrollToY(y = 0) {
|
|
|
1454
1454
|
});
|
|
1455
1455
|
}
|
|
1456
1456
|
|
|
1457
|
+
// src/useScrolled/useScrolled.ts
|
|
1458
|
+
import { useState as useState17 } from "react";
|
|
1459
|
+
var DEFAULT_CALLBACK = (top, left) => {
|
|
1460
|
+
return top > 0;
|
|
1461
|
+
};
|
|
1462
|
+
function useScrolled(callback = DEFAULT_CALLBACK) {
|
|
1463
|
+
const [scrolled, setScrolled] = useState17(false);
|
|
1464
|
+
const onScrolled = () => {
|
|
1465
|
+
const scrolled_ = callback(window.scrollY, window.scrollX);
|
|
1466
|
+
if (scrolled !== scrolled_) {
|
|
1467
|
+
setScrolled(scrolled_);
|
|
1468
|
+
}
|
|
1469
|
+
};
|
|
1470
|
+
useEventListener("scroll", onScrolled);
|
|
1471
|
+
useIsomorphicLayoutEffect(() => {
|
|
1472
|
+
onScrolled();
|
|
1473
|
+
}, []);
|
|
1474
|
+
return scrolled;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1457
1477
|
// src/useSearchParams/useSearchParams.ts
|
|
1458
1478
|
import { useRouter } from "next/router";
|
|
1459
1479
|
import { useCallback as useCallback4, useMemo as useMemo5 } from "react";
|
|
@@ -1666,10 +1686,10 @@ function useSearchParamsEncoded(key) {
|
|
|
1666
1686
|
}
|
|
1667
1687
|
|
|
1668
1688
|
// src/useSorting/useSorting.ts
|
|
1669
|
-
import { useEffect as useEffect22, useRef as useRef11, useState as
|
|
1689
|
+
import { useEffect as useEffect22, useRef as useRef11, useState as useState18 } from "react";
|
|
1670
1690
|
function useSorting(items_, callback_, sort_) {
|
|
1671
|
-
const [sort, setSort] =
|
|
1672
|
-
const [items, setItems] =
|
|
1691
|
+
const [sort, setSort] = useState18(sort_);
|
|
1692
|
+
const [items, setItems] = useState18(callback_(items_.slice(), sort));
|
|
1673
1693
|
const isInitialMount = useRef11(true);
|
|
1674
1694
|
useEffect22(() => {
|
|
1675
1695
|
if (isInitialMount.current) {
|
|
@@ -1687,11 +1707,11 @@ function useSorting(items_, callback_, sort_) {
|
|
|
1687
1707
|
}
|
|
1688
1708
|
|
|
1689
1709
|
// src/useSwiperIndex/useSwiperIndex.ts
|
|
1690
|
-
import { useCallback as useCallback6, useEffect as useEffect23, useState as
|
|
1710
|
+
import { useCallback as useCallback6, useEffect as useEffect23, useState as useState19 } from "react";
|
|
1691
1711
|
import { useSwiper } from "swiper/react";
|
|
1692
1712
|
function useSwiperIndex() {
|
|
1693
1713
|
const swiper = useSwiper();
|
|
1694
|
-
const [index, setIndex] =
|
|
1714
|
+
const [index, setIndex] = useState19(swiper.realIndex);
|
|
1695
1715
|
const slideTo = useCallback6((index2) => {
|
|
1696
1716
|
swiper.slideTo(index2);
|
|
1697
1717
|
}, [swiper]);
|
|
@@ -1829,6 +1849,7 @@ export {
|
|
|
1829
1849
|
useSSR,
|
|
1830
1850
|
useScroll,
|
|
1831
1851
|
useScrollTo,
|
|
1852
|
+
useScrolled,
|
|
1832
1853
|
useSearchParams,
|
|
1833
1854
|
useSearchParamsEncoded,
|
|
1834
1855
|
useSearchParamsValue,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@websolutespa/bom-mixer-hooks",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Mixer Hooks module of the BOM Repository",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bom",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"react": ">= 18.2.0",
|
|
35
35
|
"styled-components": ">= 5.3.5",
|
|
36
36
|
"swiper": ">= 8.3.2",
|
|
37
|
-
"zustand": ">= 4.
|
|
37
|
+
"zustand": ">= 4.4.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/react": "^18.0.18",
|
package/src/index.ts
CHANGED
|
@@ -37,12 +37,13 @@ export * from './usePortal/usePortal';
|
|
|
37
37
|
export * from './usePrevious/usePrevious';
|
|
38
38
|
export * from './useRealSize/useRealSize';
|
|
39
39
|
export * from './useResize/useResize';
|
|
40
|
+
export * from './useSSR/useSSR';
|
|
40
41
|
export * from './useScroll/useScroll';
|
|
41
42
|
export * from './useScrollTo/useScrollTo';
|
|
43
|
+
export * from './useScrolled/useScrolled';
|
|
42
44
|
export * from './useSearchParams/useSearchParams';
|
|
43
45
|
export * from './useSearchParamsEncoded/useSearchParamsEncoded';
|
|
44
46
|
export * from './useSorting/useSorting';
|
|
45
|
-
export * from './useSSR/useSSR';
|
|
46
47
|
export * from './useSwiperIndex/useSwiperIndex';
|
|
47
48
|
export * from './useSyncedRef/useSyncedRef';
|
|
48
49
|
export * from './useUI/useUI';
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import '@testing-library/jest-dom';
|
|
2
2
|
import { render, renderHook, screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
|
|
3
|
+
import { ILayout } from '@websolutespa/bom-core';
|
|
3
4
|
import { LayoutDefaults } from '@websolutespa/bom-mixer-mock';
|
|
4
|
-
import {
|
|
5
|
+
import { getLocalApiUrl } from '@websolutespa/bom-mixer-store';
|
|
5
6
|
import { LayoutProvider } from '../useLayout/useLayout';
|
|
6
7
|
import { useApi, useApiDelete, useApiFetch, useApiGet, useApiPatch, useApiPost, useApiPut } from './useApi';
|
|
7
8
|
|
|
8
9
|
const wrapper = (props: { children: React.ReactNode }) => (
|
|
9
|
-
<LayoutProvider layout={LayoutDefaults}>{props.children}</LayoutProvider>
|
|
10
|
+
<LayoutProvider layout={LayoutDefaults as ILayout}>{props.children}</LayoutProvider>
|
|
10
11
|
);
|
|
11
12
|
|
|
12
13
|
const defaultResponse = {
|
|
@@ -21,7 +22,7 @@ function mockFetch(
|
|
|
21
22
|
overrideResponse: Partial<typeof defaultResponse> = {}
|
|
22
23
|
) {
|
|
23
24
|
const endpoint = '/endpoint';
|
|
24
|
-
const url = `${
|
|
25
|
+
const url = `${getLocalApiUrl(endpoint)}?locale=en&market=ww`;
|
|
25
26
|
const payload = { data: 'data' };
|
|
26
27
|
const response = {
|
|
27
28
|
...defaultResponse,
|
|
@@ -37,6 +38,7 @@ function mockFetch(
|
|
|
37
38
|
method: string;
|
|
38
39
|
} = {
|
|
39
40
|
headers: {
|
|
41
|
+
'Authorization': 'Bearer STORE_BEARER',
|
|
40
42
|
'Content-Type': 'application/json',
|
|
41
43
|
},
|
|
42
44
|
method,
|
|
@@ -55,18 +57,18 @@ describe('useApi', () => {
|
|
|
55
57
|
jest.resetModules();
|
|
56
58
|
jest.resetAllMocks();
|
|
57
59
|
jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
60
|
+
jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
58
61
|
process.env = {
|
|
59
62
|
NODE_ENV: 'test',
|
|
60
63
|
NEXT_PUBLIC_URL: 'http://localhost:3000',
|
|
61
64
|
NEXT_PUBLIC_MOCK_FALLBACK_URL: 'http://localhost:3000',
|
|
62
65
|
NEXT_PUBLIC_API: '/api',
|
|
63
|
-
NEXT_PUBLIC_GOOGLE_MAP_API_KEY: 'AIzaSyDvGw6iAoKdRv8mmaC9GeT-LWLPQtA8p60',
|
|
64
66
|
STORE_URL: 'http://localhost:4000',
|
|
65
|
-
STORE_API: '/api',
|
|
66
|
-
STORE_BEARER: '7584f15d12972fb1e7695e998dd5e4c754f46c74d06a08e8d76f556adcd045e48cd52bed6faac098784471ac273ee40243194b9cff7eba3c4a768f8f41d2d51959a7f767b943c7f0170f6e5f632db523803c357083bf7a7bf03ee8e0df2d8ce5cd52e0211283b34d7781313da775018a9e950433d2b6faf711c20e5a63b25243',
|
|
67
|
+
STORE_API: '/bowl/api',
|
|
67
68
|
STORE_STRATEGY: 'mock',
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
STORE_BEARER: 'STORE_BEARER',
|
|
70
|
+
SECRET_COOKIE_PASSWORD: 'SECRET_COOKIE_PASSWORD',
|
|
71
|
+
HOOKS_SECRET: 'HOOKS_SECRET',
|
|
70
72
|
};
|
|
71
73
|
});
|
|
72
74
|
|
|
@@ -178,7 +180,7 @@ describe('useApi', () => {
|
|
|
178
180
|
);
|
|
179
181
|
};
|
|
180
182
|
render(
|
|
181
|
-
<LayoutProvider layout={LayoutDefaults}><Wrapper /></LayoutProvider>
|
|
183
|
+
<LayoutProvider layout={LayoutDefaults as ILayout}><Wrapper /></LayoutProvider>
|
|
182
184
|
);
|
|
183
185
|
expect(screen.getByTestId('loading')).toHaveTextContent('loading');
|
|
184
186
|
await waitForElementToBeRemoved(() => screen.getByTestId('loading'));
|
package/src/useApi/useApi.ts
CHANGED
|
@@ -1,58 +1,59 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { apiDelete, apiFetch, apiGet, apiPatch, apiPost, apiPut } from '@websolutespa/bom-mixer-store';
|
|
1
|
+
import { ApiRequestOptions, localApiDelete, localApiFetch, localApiGet, localApiPatch, localApiPost, localApiPut } from '@websolutespa/bom-mixer-store';
|
|
3
2
|
import { useHttpFetch } from '../useHttp/useHttp';
|
|
4
3
|
import { useLayout } from '../useLayout/useLayout';
|
|
5
4
|
|
|
6
|
-
export function useApiFetch<T =
|
|
5
|
+
export function useApiFetch<T = unknown>(pathname: string, options: ApiRequestOptions = {}) {
|
|
7
6
|
const layout = useLayout();
|
|
8
|
-
|
|
7
|
+
// const layout = { locale: '', market: '' };
|
|
8
|
+
return useHttpFetch<T>(pathname, options, localApiFetch, layout);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export function useApiGet<T =
|
|
11
|
+
export function useApiGet<T = unknown>(pathname: string, options: ApiRequestOptions = {}) {
|
|
12
12
|
return useApiFetch<T>(pathname, { ...options, method: 'GET' });
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export function useApiPost<T =
|
|
15
|
+
export function useApiPost<T = unknown>(pathname: string, payload: unknown, options: ApiRequestOptions = {}) {
|
|
16
16
|
return useApiFetch<T>(pathname, { ...options, method: 'POST', body: payload ? JSON.stringify(payload) : undefined });
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export function useApiPut<T =
|
|
19
|
+
export function useApiPut<T = unknown>(pathname: string, payload: unknown, options: ApiRequestOptions = {}) {
|
|
20
20
|
return useApiFetch<T>(pathname, { ...options, method: 'PUT', body: payload ? JSON.stringify(payload) : undefined });
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export function useApiPatch<T =
|
|
23
|
+
export function useApiPatch<T = unknown>(pathname: string, payload: unknown, options: ApiRequestOptions = {}) {
|
|
24
24
|
return useApiFetch<T>(pathname, { ...options, method: 'PATCH', body: payload ? JSON.stringify(payload) : undefined });
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export function useApiDelete<T =
|
|
27
|
+
export function useApiDelete<T = unknown>(pathname: string, options: ApiRequestOptions = {}) {
|
|
28
28
|
return useApiFetch<T>(pathname, { ...options, method: 'DELETE' });
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
type Api = {
|
|
32
|
-
get: <T =
|
|
33
|
-
post: <T =
|
|
34
|
-
put: <T =
|
|
35
|
-
patch: <T =
|
|
36
|
-
delete: <T =
|
|
32
|
+
get: <T = unknown>(pathname: string, options?: ApiRequestOptions) => Promise<T>;
|
|
33
|
+
post: <T = unknown>(pathname: string, payload?: unknown, options?: ApiRequestOptions) => Promise<T>;
|
|
34
|
+
put: <T = unknown>(pathname: string, payload?: unknown, options?: ApiRequestOptions) => Promise<T>;
|
|
35
|
+
patch: <T = unknown>(pathname: string, payload?: unknown, options?: ApiRequestOptions) => Promise<T>;
|
|
36
|
+
delete: <T = unknown>(pathname: string, options?: ApiRequestOptions) => Promise<T>;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
export function useApi(): Api {
|
|
40
40
|
const layout = useLayout();
|
|
41
|
+
// const layout = { locale: '', market: '' };
|
|
41
42
|
return {
|
|
42
|
-
get: async <T =
|
|
43
|
-
return
|
|
43
|
+
get: async <T = unknown>(pathname: string, options: ApiRequestOptions = {}) => {
|
|
44
|
+
return localApiGet<T>(pathname, options, layout);
|
|
44
45
|
},
|
|
45
|
-
post: async <T =
|
|
46
|
-
return
|
|
46
|
+
post: async <T = unknown>(pathname: string, payload?: unknown, options: ApiRequestOptions = {}) => {
|
|
47
|
+
return localApiPost<T>(pathname, payload, options, layout);
|
|
47
48
|
},
|
|
48
|
-
put: async <T =
|
|
49
|
-
return
|
|
49
|
+
put: async <T = unknown>(pathname: string, payload?: unknown, options: ApiRequestOptions = {}) => {
|
|
50
|
+
return localApiPut<T>(pathname, payload, options, layout);
|
|
50
51
|
},
|
|
51
|
-
patch: async <T =
|
|
52
|
-
return
|
|
52
|
+
patch: async <T = unknown>(pathname: string, payload?: unknown, options: ApiRequestOptions = {}) => {
|
|
53
|
+
return localApiPatch<T>(pathname, payload, options, layout);
|
|
53
54
|
},
|
|
54
|
-
delete: async <T =
|
|
55
|
-
return
|
|
55
|
+
delete: async <T = unknown>(pathname: string, options: ApiRequestOptions = {}) => {
|
|
56
|
+
return localApiDelete<T>(pathname, options, layout);
|
|
56
57
|
},
|
|
57
58
|
};
|
|
58
59
|
}
|
package/src/useCart/useCart.tsx
CHANGED
|
@@ -119,13 +119,10 @@ function CartProvider({ children, ...props }: CartProviderProps) {
|
|
|
119
119
|
);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
function useCart<T>(
|
|
123
|
-
selector: (state: CartState) => T,
|
|
124
|
-
equalityFn?: (left: T, right: T) => boolean
|
|
125
|
-
): T {
|
|
122
|
+
function useCart<T>(selector: (state: CartState) => T): T {
|
|
126
123
|
const store = useContext(CartContext);
|
|
127
124
|
if (!store) throw new Error('Missing CartContext.Provider in the tree');
|
|
128
|
-
return useStore(store, selector
|
|
125
|
+
return useStore(store, selector);
|
|
129
126
|
}
|
|
130
127
|
|
|
131
128
|
export { CartProvider, useCart };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IAddressOptions, ICheckoutPartial } from '@websolutespa/bom-mixer-models';
|
|
2
2
|
import { createContext, useContext, useRef } from 'react';
|
|
3
3
|
import { createStore, useStore } from 'zustand';
|
|
4
|
-
import { createJSONStorage, persist
|
|
4
|
+
import { StateStorage, createJSONStorage, persist } from 'zustand/middleware';
|
|
5
5
|
|
|
6
6
|
type CheckoutInitialProps = {
|
|
7
7
|
data: IAddressOptions;
|
|
@@ -82,13 +82,10 @@ function CheckoutProvider({ children, ...props }: CheckoutProviderProps) {
|
|
|
82
82
|
);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
function useCheckout<T>(
|
|
86
|
-
selector: (state: CheckoutState) => T,
|
|
87
|
-
equalityFn?: (left: T, right: T) => boolean
|
|
88
|
-
): T {
|
|
85
|
+
function useCheckout<T>(selector: (state: CheckoutState) => T): T {
|
|
89
86
|
const store = useContext(CheckoutContext);
|
|
90
87
|
if (!store) throw new Error('Missing CheckoutContext.Provider in the tree');
|
|
91
|
-
return useStore(store, selector
|
|
88
|
+
return useStore(store, selector);
|
|
92
89
|
}
|
|
93
90
|
|
|
94
91
|
export { CheckoutProvider, useCheckout };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { renderHook } from '@testing-library/react';
|
|
2
|
+
import { ILayout } from '@websolutespa/bom-core';
|
|
2
3
|
import { LayoutDefaults } from '@websolutespa/bom-mixer-mock';
|
|
3
4
|
import { LayoutProvider } from '../useLayout/useLayout';
|
|
4
5
|
import { useCurrency } from './useCurrency';
|
|
5
6
|
|
|
6
7
|
const wrapper = (props: { children: React.ReactNode }) => (
|
|
7
|
-
<LayoutProvider layout={LayoutDefaults}>{props.children}</LayoutProvider>
|
|
8
|
+
<LayoutProvider layout={LayoutDefaults as ILayout}>{props.children}</LayoutProvider>
|
|
8
9
|
);
|
|
9
10
|
|
|
10
11
|
describe('useCurrency', () => {
|
|
@@ -6,7 +6,7 @@ export function useCurrency(currency: string = 'EUR', locale?: string): (value:
|
|
|
6
6
|
|
|
7
7
|
/*
|
|
8
8
|
import { useMemo } from 'react';
|
|
9
|
-
import { useNumber } from '
|
|
9
|
+
import { useNumber } from '../useNumber/useNumber';
|
|
10
10
|
import { useLayout } from '../useLayout/useLayout';
|
|
11
11
|
|
|
12
12
|
export function useCurrency(currency: string = 'EUR', locale?: string): (value: number) => string {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { renderHook } from '@testing-library/react';
|
|
2
|
+
import { ILayout } from '@websolutespa/bom-core';
|
|
2
3
|
import { LayoutDefaults } from '@websolutespa/bom-mixer-mock';
|
|
3
4
|
import { LayoutProvider } from '../useLayout/useLayout';
|
|
4
5
|
import { useDateTimeFormat } from './useDateTimeFormat';
|
|
5
6
|
|
|
6
7
|
const wrapper = (props: { children: React.ReactNode }) => (
|
|
7
|
-
<LayoutProvider layout={LayoutDefaults}>{props.children}</LayoutProvider>
|
|
8
|
+
<LayoutProvider layout={LayoutDefaults as ILayout}>{props.children}</LayoutProvider>
|
|
8
9
|
);
|
|
9
10
|
|
|
10
11
|
describe('useDateTimeFormat', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '@testing-library/jest-dom';
|
|
2
2
|
import { render, screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
|
|
3
|
-
import {
|
|
3
|
+
import { getLocalApiUrl } from '@websolutespa/bom-mixer-store';
|
|
4
4
|
import { useHttpDelete, useHttpFetch, useHttpGet, useHttpPatch, useHttpPost, useHttpPut } from './useHttp';
|
|
5
5
|
|
|
6
6
|
const defaultResponse = {
|
|
@@ -12,7 +12,7 @@ const defaultResponse = {
|
|
|
12
12
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
13
|
function mockFetch(method: string = 'GET', result: any = { message: 'ok' }, overrideResponse: Partial<typeof defaultResponse> = {}) {
|
|
14
14
|
const endpoint = '/endpoint';
|
|
15
|
-
const url = `${
|
|
15
|
+
const url = `${getLocalApiUrl(endpoint)}?locale=en&market=ww`;
|
|
16
16
|
const payload = { data: 'data' };
|
|
17
17
|
const response = {
|
|
18
18
|
...defaultResponse,
|
|
@@ -45,22 +45,21 @@ describe('useHttp', () => {
|
|
|
45
45
|
const FETCH = global.fetch;
|
|
46
46
|
|
|
47
47
|
beforeEach(() => {
|
|
48
|
-
// !!! act error
|
|
49
|
-
jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
50
48
|
jest.resetModules();
|
|
51
49
|
jest.resetAllMocks();
|
|
50
|
+
jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
51
|
+
jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
52
52
|
process.env = {
|
|
53
53
|
NODE_ENV: 'test',
|
|
54
54
|
NEXT_PUBLIC_URL: 'http://localhost:3000',
|
|
55
55
|
NEXT_PUBLIC_MOCK_FALLBACK_URL: 'http://localhost:3000',
|
|
56
56
|
NEXT_PUBLIC_API: '/api',
|
|
57
|
-
NEXT_PUBLIC_GOOGLE_MAP_API_KEY: 'AIzaSyDvGw6iAoKdRv8mmaC9GeT-LWLPQtA8p60',
|
|
58
57
|
STORE_URL: 'http://localhost:4000',
|
|
59
|
-
STORE_API: '/api',
|
|
60
|
-
STORE_BEARER: '7584f15d12972fb1e7695e998dd5e4c754f46c74d06a08e8d76f556adcd045e48cd52bed6faac098784471ac273ee40243194b9cff7eba3c4a768f8f41d2d51959a7f767b943c7f0170f6e5f632db523803c357083bf7a7bf03ee8e0df2d8ce5cd52e0211283b34d7781313da775018a9e950433d2b6faf711c20e5a63b25243',
|
|
58
|
+
STORE_API: '/bowl/api',
|
|
61
59
|
STORE_STRATEGY: 'mock',
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
STORE_BEARER: 'STORE_BEARER',
|
|
61
|
+
SECRET_COOKIE_PASSWORD: 'SECRET_COOKIE_PASSWORD',
|
|
62
|
+
HOOKS_SECRET: 'HOOKS_SECRET',
|
|
64
63
|
};
|
|
65
64
|
});
|
|
66
65
|
|
package/src/useHttp/useHttp.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { FetchRequestOptions, FetchService, httpFetch } from '@websolutespa/bom-core';
|
|
1
|
+
import { FetchError, FetchRequestOptions, FetchService, httpFetch } from '@websolutespa/bom-core';
|
|
2
2
|
import { Dispatch, useEffect, useState } from 'react';
|
|
3
3
|
|
|
4
|
-
export function useHttpFetch<T =
|
|
4
|
+
export function useHttpFetch<T = unknown>(
|
|
5
5
|
pathname: string,
|
|
6
6
|
options: FetchRequestOptions = { method: 'GET' },
|
|
7
7
|
service: FetchService<T> = httpFetch,
|
|
8
|
-
serviceOptions?:
|
|
9
|
-
): [T | undefined, boolean,
|
|
8
|
+
serviceOptions?: unknown
|
|
9
|
+
): [T | undefined, boolean, FetchError, Dispatch<FetchError>] {
|
|
10
10
|
const [response, setResponse] = useState<T>();
|
|
11
11
|
const [loading, setLoading] = useState<boolean>(false);
|
|
12
|
-
const [error, setError] = useState<
|
|
12
|
+
const [error, setError] = useState<FetchError>(null);
|
|
13
13
|
useEffect(() => {
|
|
14
14
|
// const source = axios.CancelToken.source();
|
|
15
15
|
const fetchData = async () => {
|
|
@@ -19,7 +19,7 @@ export function useHttpFetch<T = any>(
|
|
|
19
19
|
const response = await service(pathname, options, serviceOptions);
|
|
20
20
|
// console.log('useHttp.response', response);
|
|
21
21
|
setResponse(response);
|
|
22
|
-
} catch (error) {
|
|
22
|
+
} catch (error: FetchError) {
|
|
23
23
|
// console.error(error)
|
|
24
24
|
setError(error);
|
|
25
25
|
}
|
|
@@ -31,22 +31,22 @@ export function useHttpFetch<T = any>(
|
|
|
31
31
|
return [response, loading, error, setError];
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export function useHttpGet<T =
|
|
34
|
+
export function useHttpGet<T = unknown>(pathname: string, options: FetchRequestOptions = {}) {
|
|
35
35
|
return useHttpFetch<T>(pathname, { ...options, method: 'GET' });
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export function useHttpPost<T =
|
|
38
|
+
export function useHttpPost<T = unknown>(pathname: string, payload: unknown, options: FetchRequestOptions = {}) {
|
|
39
39
|
return useHttpFetch<T>(pathname, { ...options, method: 'POST', body: payload ? JSON.stringify(payload) : undefined });
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
export function useHttpPut<T =
|
|
42
|
+
export function useHttpPut<T = unknown>(pathname: string, payload: unknown, options: FetchRequestOptions = {}) {
|
|
43
43
|
return useHttpFetch<T>(pathname, { ...options, method: 'PUT', body: payload ? JSON.stringify(payload) : undefined });
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
export function useHttpPatch<T =
|
|
46
|
+
export function useHttpPatch<T = unknown>(pathname: string, payload: unknown, options: FetchRequestOptions = {}) {
|
|
47
47
|
return useHttpFetch<T>(pathname, { ...options, method: 'PATCH', body: payload ? JSON.stringify(payload) : undefined });
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
export function useHttpDelete<T =
|
|
50
|
+
export function useHttpDelete<T = unknown>(pathname: string, options: FetchRequestOptions = {}) {
|
|
51
51
|
return useHttpFetch<T>(pathname, { ...options, method: 'DELETE' });
|
|
52
52
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { renderHook } from '@testing-library/react';
|
|
2
|
+
import { ILayout } from '@websolutespa/bom-core';
|
|
2
3
|
import { LayoutDefaults } from '@websolutespa/bom-mixer-mock';
|
|
3
4
|
import { LayoutProvider } from '../useLayout/useLayout';
|
|
4
5
|
import { LabelProvider, parseParams, useLabel } from './useLabel';
|
|
5
6
|
|
|
6
7
|
const wrapper = (props: { children: React.ReactNode }) => (
|
|
7
|
-
<LayoutProvider layout={LayoutDefaults}>
|
|
8
|
+
<LayoutProvider layout={LayoutDefaults as ILayout}>
|
|
8
9
|
<LabelProvider>{props.children}</LabelProvider>
|
|
9
10
|
</LayoutProvider>
|
|
10
11
|
);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// readme https://testing-library.com/
|
|
2
2
|
import { renderHook } from '@testing-library/react';
|
|
3
|
+
import { ILayout } from '@websolutespa/bom-core';
|
|
3
4
|
import { LayoutDefaults } from '@websolutespa/bom-mixer-mock';
|
|
4
5
|
import { LayoutProvider, useLayout } from './useLayout';
|
|
5
6
|
|
|
6
7
|
const wrapper = (props: { children: React.ReactNode }) => (
|
|
7
|
-
<LayoutProvider layout={LayoutDefaults}>{props.children}</LayoutProvider>
|
|
8
|
+
<LayoutProvider layout={LayoutDefaults as ILayout}>{props.children}</LayoutProvider>
|
|
8
9
|
);
|
|
9
10
|
|
|
10
11
|
describe('useLayout', () => {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { renderHook } from '@testing-library/react';
|
|
2
|
+
import { ILayout } from '@websolutespa/bom-core';
|
|
2
3
|
import { LayoutDefaults } from '@websolutespa/bom-mixer-mock';
|
|
3
4
|
import { LayoutProvider } from '../useLayout/useLayout';
|
|
4
5
|
import { useNumber } from './useNumber';
|
|
5
6
|
|
|
6
7
|
const wrapper = (props: { children: React.ReactNode }) => (
|
|
7
|
-
<LayoutProvider layout={LayoutDefaults}>{props.children}</LayoutProvider>
|
|
8
|
+
<LayoutProvider layout={LayoutDefaults as ILayout}>{props.children}</LayoutProvider>
|
|
8
9
|
);
|
|
9
10
|
|
|
10
11
|
describe('useNumber', () => {
|
package/src/usePage/usePage.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import { act, renderHook } from '@testing-library/react';
|
|
|
3
3
|
import { useScroll } from './useScroll';
|
|
4
4
|
|
|
5
5
|
const windowScroll = (scrollTop: number): void => {
|
|
6
|
-
window.
|
|
6
|
+
window.scrollY = scrollTop;
|
|
7
7
|
window.dispatchEvent(new Event('scroll'));
|
|
8
8
|
};
|
|
9
9
|
|
|
@@ -11,8 +11,8 @@ export function useScroll(): Scroll {
|
|
|
11
11
|
const [scroll, setScroll] = useState<Scroll>({ left: 0, top: 0 });
|
|
12
12
|
|
|
13
13
|
const onScroll = () => {
|
|
14
|
-
const left = window.
|
|
15
|
-
const top = window.
|
|
14
|
+
const left = window.scrollX;
|
|
15
|
+
const top = window.scrollY;
|
|
16
16
|
if (scroll.left !== left || scroll.top !== top) {
|
|
17
17
|
setScroll({ left, top });
|
|
18
18
|
}
|
|
@@ -77,8 +77,8 @@ describe('useScrollTo', () => {
|
|
|
77
77
|
left: 0,
|
|
78
78
|
}) as any);
|
|
79
79
|
scrollTo = jest.spyOn(window, 'scrollTo').mockImplementation((left: number, top: number) => {
|
|
80
|
-
window.
|
|
81
|
-
window.
|
|
80
|
+
window.scrollX = left;
|
|
81
|
+
window.scrollY = top;
|
|
82
82
|
});
|
|
83
83
|
});
|
|
84
84
|
|
|
@@ -93,13 +93,13 @@ describe('useScrollTo', () => {
|
|
|
93
93
|
|
|
94
94
|
it('should work correctly', async () => {
|
|
95
95
|
render(<Wrapper />);
|
|
96
|
-
expect(window.
|
|
96
|
+
expect(window.scrollY).toBe(0);
|
|
97
97
|
const trigger = screen.getByTestId('trigger');
|
|
98
98
|
await userEvent.click(trigger);
|
|
99
99
|
expect(scrollTo).toBeCalled();
|
|
100
100
|
expect(scrollTo).toHaveBeenCalledTimes(2);
|
|
101
101
|
expect(scrollTo).toHaveBeenCalledWith(0, 940);
|
|
102
|
-
expect(window.
|
|
102
|
+
expect(window.scrollY).toBe(940);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
});
|
|
@@ -26,12 +26,12 @@ export function scrollToSelector(selector?: string, offset: number = 0) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export function scrollToRelativeY(y: number = 0, offset: number = 0) {
|
|
29
|
-
const to = window.
|
|
29
|
+
const to = window.scrollY + y - 60 + offset;
|
|
30
30
|
return scrollToY(to);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export function scrollToY(y: number = 0) {
|
|
34
|
-
const from = window.
|
|
34
|
+
const from = window.scrollY;
|
|
35
35
|
const to = y;
|
|
36
36
|
const duration = Math.sqrt(Math.abs(to - from) / 4000);
|
|
37
37
|
animate(from, to, {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// readme https://testing-library.com/
|
|
2
|
+
import { act, renderHook } from '@testing-library/react';
|
|
3
|
+
import { useScrolled } from './useScrolled';
|
|
4
|
+
|
|
5
|
+
const windowScroll = (scrollTop: number): void => {
|
|
6
|
+
window.scrollY = scrollTop;
|
|
7
|
+
window.dispatchEvent(new Event('scroll'));
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const wrapper = (props: { children: React.ReactNode }) => (
|
|
11
|
+
<div data-testid="test" style={{ height: '2000px' }}>{props.children}</div>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
describe('useScrolled', () => {
|
|
15
|
+
|
|
16
|
+
it('should work correctly', () => {
|
|
17
|
+
const { result } = renderHook(() => useScrolled(), { wrapper });
|
|
18
|
+
expect(result.current).toStrictEqual(false);
|
|
19
|
+
act(() => {
|
|
20
|
+
windowScroll(100);
|
|
21
|
+
});
|
|
22
|
+
expect(result.current).toStrictEqual(true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should return false', () => {
|
|
26
|
+
const { result } = renderHook(() => useScrolled((top, left) => top > 200), { wrapper });
|
|
27
|
+
expect(result.current).toStrictEqual(false);
|
|
28
|
+
act(() => {
|
|
29
|
+
windowScroll(100);
|
|
30
|
+
});
|
|
31
|
+
expect(result.current).toStrictEqual(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { useEventListener } from '../useEventListener/useEventListener';
|
|
3
|
+
import { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect/useIsomorphicLayoutEffect';
|
|
4
|
+
|
|
5
|
+
const DEFAULT_CALLBACK = (top: number, left: number) => {
|
|
6
|
+
return top > 0;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function useScrolled(callback: (top: number, left: number) => boolean = DEFAULT_CALLBACK): boolean {
|
|
10
|
+
const [scrolled, setScrolled] = useState<boolean>(false);
|
|
11
|
+
|
|
12
|
+
const onScrolled = () => {
|
|
13
|
+
const scrolled_ = callback(window.scrollY, window.scrollX);
|
|
14
|
+
if (scrolled !== scrolled_) {
|
|
15
|
+
setScrolled(scrolled_);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
useEventListener('scroll', onScrolled);
|
|
20
|
+
|
|
21
|
+
// Set size at the first client-side load
|
|
22
|
+
useIsomorphicLayoutEffect(() => {
|
|
23
|
+
onScrolled();
|
|
24
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
return scrolled;
|
|
28
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { renderHook } from '@testing-library/react';
|
|
2
|
+
import { ILayout } from '@websolutespa/bom-core';
|
|
2
3
|
import { LayoutDefaults } from '@websolutespa/bom-mixer-mock';
|
|
3
4
|
import { LayoutProvider } from '../useLayout/useLayout';
|
|
4
5
|
import { useUnit } from './useUnit';
|
|
5
6
|
|
|
6
7
|
const wrapper = (props: { children: React.ReactNode }) => (
|
|
7
|
-
<LayoutProvider layout={LayoutDefaults}>{props.children}</LayoutProvider>
|
|
8
|
+
<LayoutProvider layout={LayoutDefaults as ILayout}>{props.children}</LayoutProvider>
|
|
8
9
|
);
|
|
9
10
|
|
|
10
11
|
describe('useUnit', () => {
|