UNPKG

3.38 kBTypeScriptView Raw
1import React, { useContext } from 'react';
2import type { LoadedClerk } from '@clerk/types';
3import IsomorphicClerk from '../isomorphicClerk';
4import {
5 assertClerkLoadedGuarantee,
6 assertWrappedByClerkProvider,
7} from './assertHelpers';
8import {
9 StructureContext,
10 StructureContextStates,
11} from '../contexts/StructureContext';
12import { inBrowser } from '../utils';
13import { hocChildrenNotAFunctionError } from '../errors';
14
15type IsomorphicClerkContextValue = {
16 value: IsomorphicClerk;
17};
18export const IsomorphicClerkContext = React.createContext<
19 IsomorphicClerkContextValue | undefined
20>(undefined);
21IsomorphicClerkContext.displayName = 'IsomorphicClerkContext';
22
23export const useClerk = (): LoadedClerk => {
24 const structureCtx = useContext(StructureContext);
25 const clerkCtx = useContext(IsomorphicClerkContext);
26 assertWrappedByClerkProvider(structureCtx);
27 assertWrappedByClerkProvider(clerkCtx);
28 assertClerkLoadedGuarantee(structureCtx.guaranteedLoaded, 'useClerk()');
29 assertClerkLoadedGuarantee(clerkCtx.value, 'useClerk()');
30 // The value is an instance of IsomorphicClerk, not Clerk
31 // TODO: Remove type cast
32 return (clerkCtx.value as unknown) as LoadedClerk;
33};
34
35export const withClerk = <P extends { clerk: LoadedClerk }>(
36 Component: React.ComponentType<P>,
37 displayName?: string,
38) => {
39 displayName =
40 displayName || Component.displayName || Component.name || 'Component';
41 Component.displayName = displayName;
42 const HOC = (props: Omit<P, 'clerk'>) => {
43 const structureCtx = useContext(StructureContext);
44 const clerkCtx = useContext(IsomorphicClerkContext);
45
46 if (!inBrowser()) {
47 return null;
48 }
49
50 assertWrappedByClerkProvider(structureCtx);
51 assertWrappedByClerkProvider(clerkCtx);
52
53 const clerk = (clerkCtx.value as unknown) as LoadedClerk;
54 if (!clerk) {
55 return null;
56 }
57
58 if (structureCtx.guaranteedLoaded) {
59 return <Component {...(props as P)} clerk={clerk} />;
60 }
61
62 if (clerk.client) {
63 return (
64 <StructureContext.Provider
65 value={StructureContextStates.guaranteedLoaded}
66 >
67 <Component {...(props as P)} clerk={clerk} />
68 </StructureContext.Provider>
69 );
70 }
71
72 return null;
73 };
74 HOC.displayName = `withClerk(${displayName})`;
75 return HOC;
76};
77
78export const WithClerk: React.FC<{
79 children: (clerk: LoadedClerk) => React.ReactNode;
80}> = ({ children }) => (
81 <StructureContext.Consumer>
82 {structureCtx => (
83 <IsomorphicClerkContext.Consumer>
84 {clerkCtx => {
85 if (typeof children !== 'function') {
86 throw new Error(hocChildrenNotAFunctionError);
87 }
88
89 assertWrappedByClerkProvider(structureCtx);
90 assertWrappedByClerkProvider(clerkCtx);
91
92 const clerk = (clerkCtx.value as unknown) as LoadedClerk;
93 if (!clerk) {
94 return null;
95 }
96
97 if (structureCtx.guaranteedLoaded) {
98 return children(clerk);
99 }
100
101 if (clerk.client) {
102 return (
103 <StructureContext.Provider
104 value={StructureContextStates.guaranteedLoaded}
105 >
106 {children(clerk)}
107 </StructureContext.Provider>
108 );
109 }
110
111 return null;
112 }}
113 </IsomorphicClerkContext.Consumer>
114 )}
115 </StructureContext.Consumer>
116);