diff --git a/packages/widget/src/stores/StoreProvider.tsx b/packages/widget/src/stores/StoreProvider.tsx index 58f9883d9..96c6639c5 100644 --- a/packages/widget/src/stores/StoreProvider.tsx +++ b/packages/widget/src/stores/StoreProvider.tsx @@ -1,5 +1,6 @@ import type { PropsWithChildren } from 'react'; import type { WidgetConfigProps } from '../types'; +import { ChainOrderStoreProvider } from './chains'; import { HeaderStoreProvider } from './header'; import { RouteExecutionStoreProvider } from './routes'; import { SplitSubvariantStoreProvider } from './settings'; @@ -13,9 +14,11 @@ export const StoreProvider: React.FC> = ({ state={config.subvariant === 'split' ? 'swap' : undefined} > - - {children} - + + + {children} + + ); diff --git a/packages/widget/src/stores/chains/ChainOrderStore.tsx b/packages/widget/src/stores/chains/ChainOrderStore.tsx new file mode 100644 index 000000000..ff8168bf1 --- /dev/null +++ b/packages/widget/src/stores/chains/ChainOrderStore.tsx @@ -0,0 +1,49 @@ +import { createContext, useContext, useRef } from 'react'; +import type { StoreApi, UseBoundStore } from 'zustand'; +import type { PersistStoreProviderProps } from '../types'; +import { createChainOrderStore } from './createChainOrderStore'; +import type { ChainOrderState } from './types'; + +export type ChainOrderStore = UseBoundStore>; + +export const ChainOrderStoreContext = createContext( + null, +); + +export function ChainOrderStoreProvider({ + children, + ...props +}: PersistStoreProviderProps) { + const storeRef = useRef(); + if (!storeRef.current) { + storeRef.current = createChainOrderStore(props); + } + return ( + + {children} + + ); +} + +export function useChainOrderStore( + selector: (state: ChainOrderState) => T, + equalityFn?: (left: T, right: T) => boolean, +): T { + const useStore = useContext(ChainOrderStoreContext); + if (!useStore) { + throw new Error( + `You forgot to wrap your component in <${ChainOrderStoreProvider.name}>.`, + ); + } + return useStore(selector, equalityFn); +} + +export function useChainOrderStoreContext() { + const useStore = useContext(ChainOrderStoreContext); + if (!useStore) { + throw new Error( + `You forgot to wrap your component in <${ChainOrderStoreProvider.name}>.`, + ); + } + return useStore; +} diff --git a/packages/widget/src/stores/chains/createChainOrderStore.ts b/packages/widget/src/stores/chains/createChainOrderStore.ts new file mode 100644 index 000000000..7e6c8cc36 --- /dev/null +++ b/packages/widget/src/stores/chains/createChainOrderStore.ts @@ -0,0 +1,66 @@ +import type { StateCreator } from 'zustand'; +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; +import type { PersistStoreProps } from '../types'; +import type { ChainOrderState } from './types'; + +export const maxChainToOrder = 9; + +export const createChainOrderStore = ({ namePrefix }: PersistStoreProps) => + create( + persist( + (set, get) => ({ + chainOrder: [], + availableChains: [], + initializeChains: (chainIds: number[]) => { + set((state: ChainOrderState) => { + const chainOrder = state.chainOrder.filter((chainId) => + chainIds.includes(chainId), + ); + const chainsToAdd = chainIds.filter( + (chainId) => !chainOrder.includes(chainId), + ); + if (chainOrder.length === maxChainToOrder || !chainsToAdd.length) { + return { + availableChains: chainIds, + chainOrder, + }; + } + const chainsToAddLength = maxChainToOrder - chainOrder.length; + for (let index = 0; index < chainsToAddLength; index++) { + chainOrder.push(chainsToAdd[index]); + } + return { + availableChains: chainIds, + chainOrder, + }; + }); + return get().chainOrder; + }, + setChain: (chainId: number) => { + const state = get(); + if ( + state.chainOrder.includes(chainId) || + !state.availableChains.includes(chainId) + ) { + return; + } + set((state: ChainOrderState) => { + const chainOrder = state.chainOrder.slice(); + chainOrder.unshift(chainId); + if (chainOrder.length > maxChainToOrder) { + chainOrder.pop(); + } + return { + chainOrder, + }; + }); + }, + }), + { + name: `${namePrefix || 'li.fi'}-widget-chains-order`, + version: 0, + partialize: (state) => ({ chainOrder: state.chainOrder }), + }, + ) as StateCreator, + ); diff --git a/packages/widget/src/stores/chains/index.ts b/packages/widget/src/stores/chains/index.ts index 1c9d32297..b57473872 100644 --- a/packages/widget/src/stores/chains/index.ts +++ b/packages/widget/src/stores/chains/index.ts @@ -1,3 +1,4 @@ +export * from './ChainOrderStore'; +export * from './createChainOrderStore'; export * from './types'; export * from './useChainOrder'; -export * from './useChainOrderStore'; diff --git a/packages/widget/src/stores/chains/useChainOrder.ts b/packages/widget/src/stores/chains/useChainOrder.ts index 9400d6791..c0ef2d7e1 100644 --- a/packages/widget/src/stores/chains/useChainOrder.ts +++ b/packages/widget/src/stores/chains/useChainOrder.ts @@ -1,5 +1,5 @@ import { shallow } from 'zustand/shallow'; -import { useChainOrderStore } from '.'; +import { useChainOrderStore } from './ChainOrderStore'; export const useChainOrder = (): [number[], (chainId: number) => void] => { return useChainOrderStore( diff --git a/packages/widget/src/stores/chains/useChainOrderStore.ts b/packages/widget/src/stores/chains/useChainOrderStore.ts deleted file mode 100644 index 6ab1364af..000000000 --- a/packages/widget/src/stores/chains/useChainOrderStore.ts +++ /dev/null @@ -1,64 +0,0 @@ -import type { StateCreator } from 'zustand'; -import { create } from 'zustand'; -import { persist } from 'zustand/middleware'; -import type { ChainOrderState } from './types'; - -export const maxChainToOrder = 9; - -export const useChainOrderStore = create( - persist( - (set, get) => ({ - chainOrder: [], - availableChains: [], - initializeChains: (chainIds: number[]) => { - set((state: ChainOrderState) => { - const chainOrder = state.chainOrder.filter((chainId) => - chainIds.includes(chainId), - ); - const chainsToAdd = chainIds.filter( - (chainId) => !chainOrder.includes(chainId), - ); - if (chainOrder.length === maxChainToOrder || !chainsToAdd.length) { - return { - availableChains: chainIds, - chainOrder, - }; - } - const chainsToAddLength = maxChainToOrder - chainOrder.length; - for (let index = 0; index < chainsToAddLength; index++) { - chainOrder.push(chainsToAdd[index]); - } - return { - availableChains: chainIds, - chainOrder, - }; - }); - return get().chainOrder; - }, - setChain: (chainId: number) => { - const state = get(); - if ( - state.chainOrder.includes(chainId) || - !state.availableChains.includes(chainId) - ) { - return; - } - set((state: ChainOrderState) => { - const chainOrder = state.chainOrder.slice(); - chainOrder.unshift(chainId); - if (chainOrder.length > maxChainToOrder) { - chainOrder.pop(); - } - return { - chainOrder, - }; - }); - }, - }), - { - name: `li.fi-widget-chains-order`, - version: 0, - partialize: (state) => ({ chainOrder: state.chainOrder }), - }, - ) as StateCreator, -);