import * as React from "react" ; import { Hydrate , HydrateProps } from "react-query/hydration" ; import { QueryClientProvider , QueryClient } from "react-query" ; import MoonClient from "./moonClient" ; import { Nullable , PropsWithForwardRef } from "./typing" ; import { ClientFactory , getMoonStore , ILink } from "./utils/client" ; export interface IMoonContextValue { client : Nullable < MoonClient > ; store : Nullable < QueryClient > ; } export interface RquiredMoonContextValue { client : MoonClient ; store : QueryClient ; } interface IMoonProviderProps { links : ILink [ ] ; clientFactory ? : ClientFactory ; children : JSX . Element ; store ? : QueryClient ; hydrate ? : HydrateProps ; } export type PropsWithoutMoon < P > = Omit < P , "client" | "store" > ; export type PropsWithMoon < P > = P & { client : MoonClient ; } ; export const MoonContext = React . createContext < IMoonContextValue > ( { client : null , store : null } ) ; class MoonProvider extends React . Component < IMoonProviderProps > { readonly client : MoonClient ; constructor ( props ) { super ( props ) ; const { links , clientFactory } = this . props ; this . client = new MoonClient ( links , clientFactory ) ; } render ( ) { const { children , hydrate , store } = this . props ; const queryClient = getMoonStore ( store ) ; return ( < QueryClientProvider client = { queryClient } > < Hydrate { ... hydrate } > < MoonContext . Provider value = { { client : this . client , store : queryClient } } > { children } < /MoonContext.Provider> < /Hydrate> < /QueryClientProvider>); } } export function withMoon < Props extends Partial < IMoonContextValue > = any > ( WrappedComponent ) { type WrappedComponentInstance = typeof WrappedComponent extends React . ComponentClass ? InstanceType < React . ComponentClass < Props > > : ReturnType < React . FunctionComponent < Props > > ; type WrappedComponentPropsWithoutMoon = PropsWithoutMoon < Props > ; const WithMoonComponent = ( { forwardedRef , ... rest } ) => { return ( < MoonContext . Consumer > { ( { client , store } ) => { const componentProps = { client , store , ... rest } as Props ; return < WrappedComponent ref = { forwardedRef } { ... componentProps } />; } } < /MoonContext.Consumer>); } ; return React . forwardRef < WrappedComponentInstance , WrappedComponentPropsWithoutMoon > ( ( props , ref ) => { return < WithMoonComponent forwardedRef = { ref } { ... props } />; } ) ; } export default MoonProvider ;