* )
* }
* ```
*
* @example
* ### Simple pagination
*
* The following example demonstrates how to use the `fetchPrevious` and `fetchNext` helper functions to paginate through the data. The `memberships` attribute will be populated with the first page of the Organization's memberships. When the "Previous page" or "Next page" button is clicked, the `fetchPrevious` or `fetchNext` helper function will be called to fetch the previous or next page of memberships.
*
* Notice the difference between this example's pagination and the infinite pagination example above.
*
* ```tsx
* import { useOrganization } from '@clerk/react'
*
* export default function MemberList() {
* const { memberships } = useOrganization({
* memberships: {
* keepPreviousData: true, // Persist the cached data until the new data has been fetched
* },
* })
*
* if (!memberships) {
* // Handle loading state
* return null
* }
*
* return (
*
*
* return (
*
* )
* }
* ```
*/
function useOrganizationCreationDefaults(params = {}) {
useAssertWrappedByClerkProvider(HOOK_NAME$1);
const { keepPreviousData = true, enabled = true } = params;
const clerk = useClerkInstanceContext();
const user = useUserBase();
const featureEnabled = clerk.__internal_environment?.organizationSettings?.organizationCreationDefaults?.enabled ?? false;
clerk.telemetry?.record(eventMethodCalled(HOOK_NAME$1));
const { queryKey } = useOrganizationCreationDefaultsCacheKeys({ userId: user?.id ?? null });
const queryEnabled = Boolean(user) && enabled && featureEnabled && clerk.loaded;
const query = useClerkQuery({
queryKey,
queryFn: user?.getOrganizationCreationDefaults,
enabled: queryEnabled,
placeholderData: defineKeepPreviousDataFn(keepPreviousData)
});
return {
data: query.data,
error: query.error ?? null,
isLoading: query.isLoading,
isFetching: query.isFetching
};
}
//#endregion
//#region src/react/hooks/useOrganizationList.tsx
const undefinedPaginatedResource = {
data: void 0,
count: void 0,
error: void 0,
isLoading: false,
isFetching: false,
isError: false,
page: void 0,
pageCount: void 0,
fetchPage: void 0,
fetchNext: void 0,
fetchPrevious: void 0,
hasNextPage: false,
hasPreviousPage: false,
revalidate: void 0,
setData: void 0
};
/**
* The `useOrganizationList()` hook provides access to the current user's organization memberships, invitations, and suggestions. It also includes methods for creating new organizations and managing the active organization.
*
* @example
* ### Expanding and paginating attributes
*
* To keep network usage to a minimum, developers are required to opt-in by specifying which resource they need to fetch and paginate through. So by default, the `userMemberships`, `userInvitations`, and `userSuggestions` attributes are not populated. You must pass true or an object with the desired properties to fetch and paginate the data.
*
* ```tsx
* // userMemberships.data will never be populated
* const { userMemberships } = useOrganizationList()
*
* // Use default values to fetch userMemberships, such as initialPage = 1 and pageSize = 10
* const { userMemberships } = useOrganizationList({
* userMemberships: true,
* })
*
* // Pass your own values to fetch userMemberships
* const { userMemberships } = useOrganizationList({
* userMemberships: {
* pageSize: 20,
* initialPage: 2, // skips the first page
* },
* })
*
* // Aggregate pages in order to render an infinite list
* const { userMemberships } = useOrganizationList({
* userMemberships: {
* infinite: true,
* },
* })
* ```
*
* @example
* ### Infinite pagination
*
* The following example demonstrates how to use the `infinite` property to fetch and append new data to the existing list. The `userMemberships` attribute will be populated with the first page of the user's Organization memberships. When the "Load more" button is clicked, the `fetchNext` helper function will be called to append the next page of memberships to the list.
*
* ```tsx {{ filename: 'src/components/JoinedOrganizations.tsx' }}
* import { useOrganizationList } from '@clerk/react'
* import React from 'react'
*
* const JoinedOrganizations = () => {
* const { isLoaded, setActive, userMemberships } = useOrganizationList({
* userMemberships: {
* infinite: true,
* },
* })
*
* if (!isLoaded) {
* return <>Loading>
* }
*
* return (
* <>
*
* {userMemberships.data?.map((mem) => (
*
* {mem.organization.name}
*
*
* ))}
*
*
*
* >
* )
* }
*
* export default JoinedOrganizations
* ```
*
* @example
* ### Simple pagination
*
* The following example demonstrates how to use the `fetchPrevious` and `fetchNext` helper functions to paginate through the data. The `userInvitations` attribute will be populated with the first page of invitations. When the "Previous page" or "Next page" button is clicked, the `fetchPrevious` or `fetchNext` helper function will be called to fetch the previous or next page of invitations.
*
* Notice the difference between this example's pagination and the infinite pagination example above.
*
* ```tsx {{ filename: 'src/components/UserInvitationsTable.tsx' }}
* import { useOrganizationList } from '@clerk/react'
* import React from 'react'
*
* const UserInvitationsTable = () => {
* const { isLoaded, userInvitations } = useOrganizationList({
* userInvitations: {
* infinite: true,
* keepPreviousData: true,
* },
* })
*
* if (!isLoaded || userInvitations.isLoading) {
* return <>Loading>
* }
*
* return (
* <>
*
This session has been active since {session.lastActiveAt.toLocaleString()}
*
* )
* }
* ```
*
*
*
*
* {@include ../../../docs/use-session.md#nextjs-01}
*
*
*
*/
const useSession = () => {
useAssertWrappedByClerkProvider(hookName$2);
const session = useSessionBase();
const clerk = useClerkInstanceContext();
clerk.telemetry?.record(eventMethodCalled(hookName$2));
if (session === void 0) return {
isLoaded: false,
isSignedIn: void 0,
session: void 0
};
if (session === null) return {
isLoaded: true,
isSignedIn: false,
session: null
};
return {
isLoaded: true,
isSignedIn: clerk.isSignedIn,
session
};
};
//#endregion
//#region src/react/hooks/base/useClientBase.ts
const initialSnapshot = void 0;
const getInitialSnapshot = () => initialSnapshot;
function useClientBase() {
const clerk = useClerkInstanceContext();
return useSyncExternalStore(useCallback((callback) => clerk.addListener(callback, { skipInitialEmit: true }), [clerk]), useCallback(() => {
if (!clerk.loaded || !clerk.__internal_lastEmittedResources) return initialSnapshot;
return clerk.__internal_lastEmittedResources.client;
}, [clerk]), getInitialSnapshot);
}
//#endregion
//#region src/react/hooks/useSessionList.ts
const hookName$1 = "useSessionList";
/**
* The `useSessionList()` hook returns an array of [`Session`](https://clerk.com/docs/reference/objects/session) objects that have been registered on the client device.
*
* @unionReturnHeadings
* ["Initialization", "Loaded"]
*
* @function
*
* @example
* ### Get a list of sessions
*
* The following example uses `useSessionList()` to get a list of sessions that have been registered on the client device. The `sessions` property is used to show the number of times the user has visited the page.
*
*
*
*
* ```tsx {{ filename: 'src/Home.tsx' }}
* import { useSessionList } from '@clerk/react'
*
* export default function Home() {
* const { isLoaded, sessions } = useSessionList()
*
* if (!isLoaded) {
* // Handle loading state
* return null
* }
*
* return (
*
*
Welcome back. You've been here {sessions.length} times before.
*
* )
* }
* ```
*
*
*
*
* {@include ../../../docs/use-session-list.md#nextjs-01}
*
*
*
*/
const useSessionList = () => {
useAssertWrappedByClerkProvider(hookName$1);
const isomorphicClerk = useClerkInstanceContext();
const client = useClientBase();
useClerkInstanceContext().telemetry?.record(eventMethodCalled(hookName$1));
if (!client) return {
isLoaded: false,
sessions: void 0,
setActive: void 0
};
return {
isLoaded: true,
sessions: client.sessions,
setActive: isomorphicClerk.setActive
};
};
//#endregion
//#region src/react/hooks/useUser.ts
const hookName = "useUser";
/**
* The `useUser()` hook provides access to the current user's [`User`](https://clerk.com/docs/reference/objects/user) object, which contains all the data for a single user in your application and provides methods to manage their account. This hook also allows you to check if the user is signed in and if Clerk has loaded and initialized.
*
* @unionReturnHeadings
* ["Initialization", "Signed out", "Signed in"]
*
* @example
* ### Get the current user
*
* The following example uses the `useUser()` hook to access the [`User`](https://clerk.com/docs/reference/objects/user) object, which contains the current user's data such as their full name. The `isLoaded` and `isSignedIn` properties are used to handle the loading state and to check if the user is signed in, respectively.
*
* ```tsx {{ filename: 'src/Example.tsx' }}
* import { useUser } from '@clerk/react'
*
* export default function Example() {
* const { isSignedIn, user, isLoaded } = useUser()
*
* if (!isLoaded) {
* return
Loading...
* }
*
* if (!isSignedIn) {
* return
Sign in to view this page
* }
*
* return
Hello {user.firstName}!
* }
* ```
*
* @example
* ### Update user data
*
* The following example uses the `useUser()` hook to access the [`User`](https://clerk.com/docs/reference/objects/user) object, which calls the [`update()`](https://clerk.com/docs/reference/objects/user#update) method to update the current user's information.
*
*
*
*
* ```tsx {{ filename: 'src/Home.tsx' }}
* import { useUser } from '@clerk/react'
*
* export default function Home() {
* const { isSignedIn, isLoaded, user } = useUser()
*
* if (!isLoaded) {
* // Handle loading state
* return null
* }
*
* if (!isSignedIn) return null
*
* const updateUser = async () => {
* await user.update({
* firstName: 'John',
* lastName: 'Doe',
* })
* }
*
* return (
* <>
*
*
user.firstName: {user.firstName}
*
user.lastName: {user.lastName}
* >
* )
* }
* ```
*
*
*
* {@include ../../../docs/use-user.md#nextjs-01}
*
*
*
*
* @example
* ### Reload user data
*
* The following example uses the `useUser()` hook to access the [`User`](https://clerk.com/docs/reference/objects/user) object, which calls the [`reload()`](https://clerk.com/docs/reference/objects/user#reload) method to get the latest user's information.
*
*
*
*
* ```tsx {{ filename: 'src/Home.tsx' }}
* import { useUser } from '@clerk/react'
*
* export default function Home() {
* const { isSignedIn, isLoaded, user } = useUser();
*
* if (!isLoaded) {
* // Handle loading state
* return null;
* }
*
* if (!isSignedIn) return null;
*
* const updateUser = async () => {
* // Update data via an API endpoint
* const updateMetadata = await fetch('/api/updateMetadata', {
* method: 'POST',
* body: JSON.stringify({
* role: 'admin'
* })
* });
*
* // Check if the update was successful
* if ((await updateMetadata.json()).message !== 'success') {
* throw new Error('Error updating');
* }
*
* // If the update was successful, reload the user data
* await user.reload();
* };
*
* return (
* <>
*
*
user role: {user.publicMetadata.role}
* >
* );
* }
* ```
*
*
*
*
* {@include ../../../docs/use-user.md#nextjs-02}
*
*
*
*/
function useUser() {
useAssertWrappedByClerkProvider(hookName);
const user = useUserBase();
useClerkInstanceContext().telemetry?.record(eventMethodCalled(hookName));
if (user === void 0) return {
isLoaded: false,
isSignedIn: void 0,
user: void 0
};
if (user === null) return {
isLoaded: true,
isSignedIn: false,
user: null
};
return {
isLoaded: true,
isSignedIn: true,
user
};
}
//#endregion
//#region src/react/hooks/useDeepEqualMemo.ts
const useDeepEqualMemoize = (value) => {
const ref = React.useRef(value);
if (!dequal(value, ref.current)) ref.current = value;
return React.useMemo(() => ref.current, [ref.current]);
};
/**
* @internal
*/
const useDeepEqualMemo = (factory, dependencyArray) => {
return React.useMemo(factory, useDeepEqualMemoize(dependencyArray));
};
/**
* @internal
*/
const isDeeplyEqual = dequal;
//#endregion
//#region src/react/hooks/useReverification.ts
const CLERK_API_REVERIFICATION_ERROR_CODE = "session_reverification_required";
/**
*
*/
async function resolveResult(result) {
try {
const r = await result;
if (r instanceof Response) return r.json();
return r;
} catch (e) {
if (isClerkAPIResponseError(e) && e.errors.find(({ code }) => code === CLERK_API_REVERIFICATION_ERROR_CODE)) return reverificationError();
throw e;
}
}
/**
*
*/
function createReverificationHandler(params) {
/**
*
*/
function assertReverification(fetcher) {
return (async (...args) => {
let result = await resolveResult(fetcher(...args));
if (isReverificationHint(result)) {
/**
* Create a promise
*/
const resolvers = createDeferredPromise();
const isValidMetadata = validateReverificationConfig(result.clerk_error.metadata?.reverification);
const level = isValidMetadata ? isValidMetadata().level : void 0;
const cancel = () => {
resolvers.reject(new ClerkRuntimeError("User cancelled attempted verification", { code: "reverification_cancelled" }));
};
const complete = () => {
resolvers.resolve(true);
};
if (params.onNeedsReverification === void 0)
/**
* On success resolve the pending promise
* On cancel reject the pending promise
*/
params.openUIComponent?.({
level,
afterVerification: complete,
afterVerificationCancelled: cancel
});
else params.onNeedsReverification({
cancel,
complete,
level
});
/**
* Wait until the promise from above have been resolved or rejected
*/
await resolvers.promise;
/**
* After the promise resolved successfully try the original request one more time
*/
result = await resolveResult(fetcher(...args));
}
return result;
});
}
return assertReverification;
}
/**
* > [!WARNING]
* >
* > Depending on the SDK you're using, this feature requires `@clerk/nextjs@6.12.7` or later, `@clerk/react@5.25.1` or later, and `@clerk/clerk-js@5.57.1` or later.
*
* The `useReverification()` hook is used to handle a session's reverification flow. If a request requires reverification, a modal will display, prompting the user to verify their credentials. Upon successful verification, the original request will automatically retry.
*
* @function
*
* @returns The `useReverification()` hook returns an array with the "enhanced" fetcher.
*
* @example
* ### Handle cancellation of the reverification process
*
* The following example demonstrates how to handle scenarios where a user cancels the reverification flow, such as closing the modal, which might result in `myData` being `null`.
*
* In the following example, `myFetcher` would be a function in your backend that fetches data from the route that requires reverification. See the [guide on how to require reverification](https://clerk.com/docs/guides/secure/reverification) for more information.
*
* ```tsx {{ filename: 'src/components/MyButton.tsx' }}
* import { useReverification } from '@clerk/react'
* import { isReverificationCancelledError } from '@clerk/react/error'
*
* type MyData = {
* balance: number
* }
*
* export function MyButton() {
* const fetchMyData = () => fetch('/api/balance').then(res=> res.json() as Promise)
* const enhancedFetcher = useReverification(fetchMyData);
*
* const handleClick = async () => {
* try {
* const myData = await enhancedFetcher()
* // ^ is types as `MyData`
* } catch (e) {
* // Handle error returned from the fetcher here
*
* // You can also handle cancellation with the following
* if (isReverificationCancelledError(err)) {
* // Handle the cancellation error here
* }
* }
* }
*
* return
* }
* ```
*/
const useReverification = (fetcher, options) => {
const { __internal_openReverification, telemetry } = useClerk();
const fetcherRef = useRef(fetcher);
const optionsRef = useRef(options);
telemetry?.record(eventMethodCalled("useReverification", { onNeedsReverification: Boolean(options?.onNeedsReverification) }));
useSafeLayoutEffect(() => {
fetcherRef.current = fetcher;
optionsRef.current = options;
});
return useCallback((...args) => {
return createReverificationHandler({
openUIComponent: __internal_openReverification,
telemetry,
...optionsRef.current
})(fetcherRef.current)(...args);
}, [__internal_openReverification, telemetry]);
};
//#endregion
//#region src/react/hooks/useBillingIsEnabled.ts
/**
* @internal
*/
function useBillingIsEnabled(params) {
const clerk = useClerkInstanceContext();
const enabledFromParam = params?.enabled ?? true;
const environment = clerk.__internal_environment;
const user = useUserBase();
const organization = useOrganizationBase();
const userBillingEnabled = environment?.commerceSettings.billing.user.enabled;
const orgBillingEnabled = environment?.commerceSettings.billing.organization.enabled;
const billingEnabled = params?.for === "organization" ? orgBillingEnabled : params?.for === "user" ? userBillingEnabled : userBillingEnabled || orgBillingEnabled;
const isOrganization = params?.for === "organization";
const requireUserAndOrganizationWhenAuthenticated = params?.authenticated ?? true ? (isOrganization ? Boolean(organization?.id) : true) && Boolean(user?.id) : true;
return billingEnabled && enabledFromParam && clerk.loaded && requireUserAndOrganizationWhenAuthenticated;
}
//#endregion
//#region src/react/hooks/createBillingPaginatedHook.tsx
/**
* A hook factory that creates paginated data fetching hooks for commerce-related resources.
* It provides a standardized way to create hooks that can fetch either user or Organization resources
* with built-in pagination support.
*
* The generated hooks handle:
* - Clerk authentication context
* - Resource-specific data fetching
* - Pagination (both traditional and infinite scroll)
* - Telemetry tracking
* - Type safety for the specific resource.
*
* @internal
*/
function createBillingPaginatedHook({ hookName: hookName$3, resourceType, useFetcher, options }) {
return function useBillingHook(params) {
const { for: _for, enabled: externalEnabled,...paginationParams } = params || {};
const safeFor = _for || "user";
useAssertWrappedByClerkProvider(hookName$3);
const fetchFn = useFetcher(safeFor);
const safeValues = useWithSafeValues(paginationParams, {
initialPage: 1,
pageSize: 10,
keepPreviousData: false,
infinite: false,
__experimental_mode: void 0
});
const clerk = useClerkInstanceContext();
const user = useUserBase();
const organization = useOrganizationBase();
clerk.telemetry?.record(eventMethodCalled(hookName$3));
const isForOrganization = safeFor === "organization";
const billingEnabled = useBillingIsEnabled({
for: safeFor,
enabled: externalEnabled,
authenticated: !options?.unauthenticated
});
const hookParams = typeof paginationParams === "undefined" ? void 0 : {
initialPage: safeValues.initialPage,
pageSize: safeValues.pageSize,
...options?.unauthenticated ? {} : isForOrganization ? { orgId: organization?.id } : {}
};
const isEnabled = !!hookParams && clerk.loaded && !!billingEnabled;
return usePagesOrInfinite({
fetcher: fetchFn,
config: {
keepPreviousData: safeValues.keepPreviousData,
infinite: safeValues.infinite,
enabled: isEnabled,
...options?.unauthenticated ? {} : { isSignedIn: user !== null },
__experimental_mode: safeValues.__experimental_mode,
initialPage: safeValues.initialPage,
pageSize: safeValues.pageSize
},
keys: createCacheKeys({
stablePrefix: resourceType,
authenticated: !options?.unauthenticated,
tracked: options?.unauthenticated ? { for: safeFor } : {
userId: user?.id,
...isForOrganization ? { orgId: organization?.id } : {}
},
untracked: { args: hookParams }
})
});
};
}
//#endregion
//#region src/react/hooks/useStatements.tsx
/**
* @internal
*/
const useStatements = createBillingPaginatedHook({
hookName: "useStatements",
resourceType: STABLE_KEYS.STATEMENTS_KEY,
useFetcher: () => {
const clerk = useClerkInstanceContext();
if (clerk.loaded) return clerk.billing.getStatements;
}
});
//#endregion
//#region src/react/hooks/usePaymentAttempts.tsx
/**
* @internal
*/
const usePaymentAttempts = createBillingPaginatedHook({
hookName: "usePaymentAttempts",
resourceType: STABLE_KEYS.PAYMENT_ATTEMPTS_KEY,
useFetcher: () => {
const clerk = useClerkInstanceContext();
if (clerk.loaded) return clerk.billing.getPaymentAttempts;
}
});
//#endregion
//#region src/react/hooks/usePaymentMethods.tsx
/**
* @internal
*/
const usePaymentMethods = createBillingPaginatedHook({
hookName: "usePaymentMethods",
resourceType: STABLE_KEYS.PAYMENT_METHODS_KEY,
useFetcher: (resource) => {
const organization = useOrganizationBase();
const user = useUserBase();
if (resource === "organization") return organization?.getPaymentMethods;
return user?.getPaymentMethods;
}
});
//#endregion
//#region src/react/hooks/usePlans.tsx
/**
* @internal
*/
const usePlans = createBillingPaginatedHook({
hookName: "usePlans",
resourceType: STABLE_KEYS.PLANS_KEY,
useFetcher: (_for) => {
const clerk = useClerkInstanceContext();
if (!clerk.loaded) return;
return (params) => clerk.billing.getPlans({
...params,
for: _for
});
},
options: { unauthenticated: true }
});
//#endregion
//#region src/react/hooks/useSubscription.shared.ts
function useSubscriptionCacheKeys(params) {
const { userId, orgId, for: forType } = params;
return useMemo(() => {
const safeOrgId = forType === "organization" ? orgId : void 0;
return createCacheKeys({
stablePrefix: STABLE_KEYS.SUBSCRIPTION_KEY,
authenticated: true,
tracked: {
userId,
orgId: safeOrgId
},
untracked: { args: { orgId: safeOrgId } }
});
}, [
userId,
orgId,
forType
]);
}
//#endregion
//#region src/react/hooks/useSubscription.tsx
const HOOK_NAME = "useSubscription";
/**
* @internal
*/
function useSubscription(params) {
useAssertWrappedByClerkProvider(HOOK_NAME);
const clerk = useClerkInstanceContext();
const user = useUserBase();
const organization = useOrganizationBase();
const billingEnabled = useBillingIsEnabled(params);
const recordedRef = useRef(false);
useEffect(() => {
if (!recordedRef.current && clerk?.telemetry) {
clerk.telemetry.record(eventMethodCalled(HOOK_NAME));
recordedRef.current = true;
}
}, [clerk]);
const keepPreviousData = params?.keepPreviousData ?? false;
const [queryClient] = useClerkQueryClient();
const { queryKey, invalidationKey, stableKey, authenticated } = useSubscriptionCacheKeys({
userId: user?.id,
orgId: organization?.id,
for: params?.for
});
const queriesEnabled = Boolean(user?.id && billingEnabled);
useClearQueriesOnSignOut({
isSignedOut: user === null,
authenticated,
stableKeys: stableKey
});
const query = useClerkQuery({
queryKey,
queryFn: ({ queryKey: queryKey$1 }) => {
const obj = queryKey$1[3];
return clerk.billing.getSubscription(obj.args);
},
staleTime: 1e3 * 60,
enabled: queriesEnabled,
placeholderData: defineKeepPreviousDataFn(keepPreviousData && queriesEnabled)
});
const revalidate = useCallback(() => queryClient.invalidateQueries({ queryKey: invalidationKey }), [queryClient, invalidationKey]);
return {
data: query.data,
error: query.error ?? void 0,
isLoading: query.isLoading,
isFetching: query.isFetching,
revalidate
};
}
//#endregion
//#region src/react/hooks/useCheckout.ts
/**
* @function
*
* @param [options] - An object containing the configuration for the checkout flow.
*
* **Required** if the hook is used without a `` wrapping the component tree.
*/
const useCheckout = (options) => {
const contextOptions = useCheckoutContext();
const { for: forOrganization, planId, planPeriod } = options || contextOptions;
const organization = useOrganizationBase();
const { isLoaded, user } = useUser();
const clerk = useClerkInstanceContext();
if (user === null && isLoaded) throw new Error("Clerk: Ensure that `useCheckout` is inside a component wrapped with ``.");
if (isLoaded && forOrganization === "organization" && organization === null) throw new Error("Clerk: Ensure your flow checks for an active organization. Retrieve `orgId` from `useAuth()` and confirm it is defined. For SSR, see: https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object");
const signal = useCallback(() => {
return clerk.__experimental_checkout({
planId,
planPeriod,
for: forOrganization
});
}, [
user?.id,
organization?.id,
planId,
planPeriod,
forOrganization
]);
const subscribe = useCallback((callback) => {
if (!clerk.loaded) return () => {};
return clerk.__internal_state.__internal_effect(() => {
signal();
callback();
});
}, [
signal,
clerk.loaded,
clerk.__internal_state
]);
const getSnapshot = useCallback(() => {
return signal();
}, [signal]);
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
};
//#endregion
//#region src/react/hooks/useStatementQuery.shared.ts
function useStatementQueryCacheKeys(params) {
const { statementId, userId, orgId, for: forType } = params;
return useMemo(() => {
return createCacheKeys({
stablePrefix: INTERNAL_STABLE_KEYS.BILLING_STATEMENTS_KEY,
authenticated: true,
tracked: {
statementId,
forType,
userId,
orgId
},
untracked: { args: {
id: statementId ?? void 0,
orgId: orgId ?? void 0
} }
});
}, [
statementId,
forType,
userId,
orgId
]);
}
//#endregion
//#region src/react/hooks/useStatementQuery.tsx
/**
* @internal
*/
function useStatementQuery(params = {}) {
const { statementId = null, keepPreviousData = false, for: forType = "user" } = params;
const clerk = useClerkInstanceContext();
const user = useUserBase();
const organization = useOrganizationBase();
const organizationId = forType === "organization" ? organization?.id ?? null : null;
const { queryKey, stableKey, authenticated } = useStatementQueryCacheKeys({
statementId,
userId: user?.id ?? null,
orgId: organizationId,
for: forType
});
const billingEnabled = useBillingIsEnabled(params);
const queryEnabled = Boolean(statementId) && billingEnabled;
useClearQueriesOnSignOut({
isSignedOut: user === null,
authenticated,
stableKeys: stableKey
});
const query = useClerkQuery({
queryKey,
queryFn: () => {
if (!statementId) throw new Error("statementId is required to fetch a statement");
return clerk.billing.getStatement({
id: statementId,
orgId: organizationId ?? void 0
});
},
enabled: queryEnabled,
placeholderData: defineKeepPreviousDataFn(keepPreviousData),
staleTime: 1e3 * 60
});
return {
data: query.data,
error: query.error ?? null,
isLoading: query.isLoading,
isFetching: query.isFetching
};
}
//#endregion
//#region src/react/hooks/usePlanDetailsQuery.shared.ts
function usePlanDetailsQueryCacheKeys(params) {
const { planId } = params;
return useMemo(() => {
return createCacheKeys({
stablePrefix: INTERNAL_STABLE_KEYS.BILLING_PLANS_KEY,
authenticated: false,
tracked: { planId: planId ?? null },
untracked: { args: { id: planId ?? void 0 } }
});
}, [planId]);
}
//#endregion
//#region src/react/hooks/usePlanDetailsQuery.tsx
/**
* @internal
*/
function __internal_usePlanDetailsQuery(params = {}) {
const { planId, initialPlan = null, keepPreviousData = true } = params;
const clerk = useClerkInstanceContext();
const targetPlanId = planId ?? initialPlan?.id ?? null;
const { queryKey } = usePlanDetailsQueryCacheKeys({ planId: targetPlanId });
const billingEnabled = useBillingIsEnabled({ authenticated: false });
const query = useClerkQuery({
queryKey,
queryFn: () => {
if (!targetPlanId) throw new Error("planId is required to fetch plan details");
return clerk.billing.getPlan({ id: targetPlanId });
},
enabled: Boolean(targetPlanId) && billingEnabled,
initialData: initialPlan ?? void 0,
placeholderData: defineKeepPreviousDataFn(keepPreviousData),
initialDataUpdatedAt: 0
});
return {
data: query.data,
error: query.error ?? null,
isLoading: query.isLoading,
isFetching: query.isFetching
};
}
//#endregion
//#region src/react/hooks/usePaymentAttemptQuery.shared.ts
function usePaymentAttemptQueryCacheKeys(params) {
const { paymentAttemptId, userId, orgId, for: forType } = params;
return useMemo(() => {
return createCacheKeys({
stablePrefix: INTERNAL_STABLE_KEYS.PAYMENT_ATTEMPT_KEY,
authenticated: true,
tracked: {
paymentAttemptId,
forType,
userId,
orgId
},
untracked: { args: {
id: paymentAttemptId ?? void 0,
orgId: orgId ?? void 0
} }
});
}, [
paymentAttemptId,
forType,
userId,
orgId
]);
}
//#endregion
//#region src/react/hooks/usePaymentAttemptQuery.tsx
/**
* @internal
*/
function usePaymentAttemptQuery(params) {
const { paymentAttemptId, keepPreviousData = false, for: forType = "user" } = params;
const clerk = useClerkInstanceContext();
const user = useUserBase();
const organization = useOrganizationBase();
const organizationId = forType === "organization" ? organization?.id ?? null : null;
const { queryKey, stableKey, authenticated } = usePaymentAttemptQueryCacheKeys({
paymentAttemptId,
userId: user?.id ?? null,
orgId: organizationId,
for: forType
});
const billingEnabled = useBillingIsEnabled(params);
const queryEnabled = Boolean(paymentAttemptId) && billingEnabled;
useClearQueriesOnSignOut({
isSignedOut: user === null,
authenticated,
stableKeys: stableKey
});
const query = useClerkQuery({
queryKey,
queryFn: ({ queryKey: queryKey$1 }) => {
const args = queryKey$1[3].args;
return clerk.billing.getPaymentAttempt(args);
},
enabled: queryEnabled,
placeholderData: defineKeepPreviousDataFn(keepPreviousData),
staleTime: 1e3 * 60
});
return {
data: query.data,
error: query.error ?? null,
isLoading: query.isLoading,
isFetching: query.isFetching
};
}
//#endregion
//#region src/react/utils.ts
function assertClerkSingletonExists(clerk) {
if (!clerk) clerkCoreErrorNoClerkSingleton();
}
//#endregion
//#region src/react/ClerkContextProvider.tsx
function ClerkContextProvider(props) {
const clerk = props.clerk;
assertClerkSingletonExists(clerk);
if (props.initialState instanceof Promise && !("use" in React && typeof React.use === "function")) throw new Error("initialState cannot be a promise if React version is less than 19");
const clerkCtx = React.useMemo(() => ({ value: clerk }), [props.clerkStatus]);
return /* @__PURE__ */ React.createElement(InitialStateProvider, { initialState: props.initialState }, /* @__PURE__ */ React.createElement(ClerkInstanceContext.Provider, { value: clerkCtx }, /* @__PURE__ */ React.createElement(__experimental_CheckoutProvider, { value: void 0 }, props.children)));
}
//#endregion
//#region src/react/stripe-react/utils.ts
const usePrevious = (value) => {
const ref = useRef(value);
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
};
const useAttachEvent = (element, event, cb) => {
const cbDefined = !!cb;
const cbRef = useRef(cb);
useEffect(() => {
cbRef.current = cb;
}, [cb]);
useEffect(() => {
if (!cbDefined || !element) return () => {};
const decoratedCb = (...args) => {
if (cbRef.current) cbRef.current(...args);
};
element.on(event, decoratedCb);
return () => {
element.off(event, decoratedCb);
};
}, [
cbDefined,
event,
element,
cbRef
]);
};
//#endregion
//#region src/react/stripe-react/index.tsx
const ElementsContext = React.createContext(null);
ElementsContext.displayName = "ElementsContext";
const parseElementsContext = (ctx, useCase) => {
if (!ctx) throw new Error(`Could not find Elements context; You need to wrap the part of your app that ${useCase} in an provider.`);
return ctx;
};
/**
* The `Elements` provider allows you to use [Element components](https://stripe.com/docs/stripe-js/react#element-components) and access the [Stripe object](https://stripe.com/docs/js/initializing) in any nested component.
* Render an `Elements` provider at the root of your React app so that it is available everywhere you need it.
*
* To use the `Elements` provider, call `loadStripe` from `@stripe/stripe-js` with your publishable key.
* The `loadStripe` function will asynchronously load the Stripe.js script and initialize a `Stripe` object.
* Pass the returned `Promise` to `Elements`.
*
* @docs https://stripe.com/docs/stripe-js/react#elements-provider
*/
const Elements = (({ stripe: rawStripeProp, options, children }) => {
const parsed = React.useMemo(() => parseStripeProp(rawStripeProp), [rawStripeProp]);
const [ctx, setContext] = React.useState(() => ({
stripe: parsed.tag === "sync" ? parsed.stripe : null,
elements: parsed.tag === "sync" ? parsed.stripe.elements(options) : null
}));
React.useEffect(() => {
let isMounted = true;
const safeSetContext = (stripe) => {
setContext((ctx$1) => {
if (ctx$1.stripe) return ctx$1;
return {
stripe,
elements: stripe.elements(options)
};
});
};
if (parsed.tag === "async" && !ctx.stripe) parsed.stripePromise.then((stripe) => {
if (stripe && isMounted) safeSetContext(stripe);
});
else if (parsed.tag === "sync" && !ctx.stripe) safeSetContext(parsed.stripe);
return () => {
isMounted = false;
};
}, [
parsed,
ctx,
options
]);
const prevStripe = usePrevious(rawStripeProp);
React.useEffect(() => {
if (prevStripe !== null && prevStripe !== rawStripeProp) console.warn("Unsupported prop change on Elements: You cannot change the `stripe` prop after setting it.");
}, [prevStripe, rawStripeProp]);
const prevOptions = usePrevious(options);
React.useEffect(() => {
if (!ctx.elements) return;
const updates = extractAllowedOptionsUpdates(options, prevOptions, ["clientSecret", "fonts"]);
if (updates) ctx.elements.update(updates);
}, [
options,
prevOptions,
ctx.elements
]);
return /* @__PURE__ */ React.createElement(ElementsContext.Provider, { value: ctx }, children);
});
const useElementsContextWithUseCase = (useCaseMessage) => {
return parseElementsContext(React.useContext(ElementsContext), useCaseMessage);
};
const useElements = () => {
const { elements } = useElementsContextWithUseCase("calls useElements()");
return elements;
};
const INVALID_STRIPE_ERROR = "Invalid prop `stripe` supplied to `Elements`. We recommend using the `loadStripe` utility from `@stripe/stripe-js`. See https://stripe.com/docs/stripe-js/react#elements-props-stripe for details.";
const validateStripe = (maybeStripe, errorMsg = INVALID_STRIPE_ERROR) => {
if (maybeStripe === null || isStripe(maybeStripe)) return maybeStripe;
throw new Error(errorMsg);
};
const parseStripeProp = (raw, errorMsg = INVALID_STRIPE_ERROR) => {
if (isPromise(raw)) return {
tag: "async",
stripePromise: Promise.resolve(raw).then((result) => validateStripe(result, errorMsg))
};
const stripe = validateStripe(raw, errorMsg);
if (stripe === null) return { tag: "empty" };
return {
tag: "sync",
stripe
};
};
const isUnknownObject = (raw) => {
return raw !== null && typeof raw === "object";
};
const isPromise = (raw) => {
return isUnknownObject(raw) && typeof raw.then === "function";
};
const isStripe = (raw) => {
return isUnknownObject(raw) && typeof raw.elements === "function" && typeof raw.createToken === "function" && typeof raw.createPaymentMethod === "function" && typeof raw.confirmCardPayment === "function";
};
const extractAllowedOptionsUpdates = (options, prevOptions, immutableKeys) => {
if (!isUnknownObject(options)) return null;
return Object.keys(options).reduce((newOptions, key) => {
const isUpdated = !isUnknownObject(prevOptions) || !isEqual(options[key], prevOptions[key]);
if (immutableKeys.includes(key)) {
if (isUpdated) console.warn(`Unsupported prop change: options.${key} is not a mutable property.`);
return newOptions;
}
if (!isUpdated) return newOptions;
return {
...newOptions || {},
[key]: options[key]
};
}, null);
};
const PLAIN_OBJECT_STR = "[object Object]";
const isEqual = (left, right) => {
if (!isUnknownObject(left) || !isUnknownObject(right)) return left === right;
const leftArray = Array.isArray(left);
if (leftArray !== Array.isArray(right)) return false;
const leftPlainObject = Object.prototype.toString.call(left) === PLAIN_OBJECT_STR;
if (leftPlainObject !== (Object.prototype.toString.call(right) === PLAIN_OBJECT_STR)) return false;
if (!leftPlainObject && !leftArray) return left === right;
const leftKeys = Object.keys(left);
const rightKeys = Object.keys(right);
if (leftKeys.length !== rightKeys.length) return false;
const keySet = {};
for (let i = 0; i < leftKeys.length; i += 1) keySet[leftKeys[i]] = true;
for (let i = 0; i < rightKeys.length; i += 1) keySet[rightKeys[i]] = true;
const allKeys = Object.keys(keySet);
if (allKeys.length !== leftKeys.length) return false;
const l = left;
const r = right;
const pred = (key) => {
return isEqual(l[key], r[key]);
};
return allKeys.every(pred);
};
const useStripe = () => {
const { stripe } = useElementsOrCheckoutSdkContextWithUseCase("calls useStripe()");
return stripe;
};
const useElementsOrCheckoutSdkContextWithUseCase = (useCaseString) => {
return parseElementsContext(React.useContext(ElementsContext), useCaseString);
};
const capitalized = (str) => str.charAt(0).toUpperCase() + str.slice(1);
const createElementComponent = (type, isServer) => {
const displayName = `${capitalized(type)}Element`;
const ClientElement = ({ id, className, fallback, options = {}, onBlur, onFocus, onReady, onChange, onEscape, onClick, onLoadError, onLoaderStart, onNetworksChange, onConfirm, onCancel, onShippingAddressChange, onShippingRateChange }) => {
const ctx = useElementsOrCheckoutSdkContextWithUseCase(`mounts <${displayName}>`);
const elements = "elements" in ctx ? ctx.elements : null;
const [element, setElement] = React.useState(null);
const elementRef = React.useRef(null);
const domNode = React.useRef(null);
const [isReady, setReady] = useState(false);
useAttachEvent(element, "blur", onBlur);
useAttachEvent(element, "focus", onFocus);
useAttachEvent(element, "escape", onEscape);
useAttachEvent(element, "click", onClick);
useAttachEvent(element, "loaderror", onLoadError);
useAttachEvent(element, "loaderstart", onLoaderStart);
useAttachEvent(element, "networkschange", onNetworksChange);
useAttachEvent(element, "confirm", onConfirm);
useAttachEvent(element, "cancel", onCancel);
useAttachEvent(element, "shippingaddresschange", onShippingAddressChange);
useAttachEvent(element, "shippingratechange", onShippingRateChange);
useAttachEvent(element, "change", onChange);
let readyCallback;
if (onReady) readyCallback = () => {
setReady(true);
onReady(element);
};
useAttachEvent(element, "ready", readyCallback);
React.useLayoutEffect(() => {
if (elementRef.current === null && domNode.current !== null && elements) {
let newElement = null;
if (elements) newElement = elements.create(type, options);
elementRef.current = newElement;
setElement(newElement);
if (newElement) newElement.mount(domNode.current);
}
}, [elements, options]);
const prevOptions = usePrevious(options);
React.useEffect(() => {
if (!elementRef.current) return;
const updates = extractAllowedOptionsUpdates(options, prevOptions, ["paymentRequest"]);
if (updates && "update" in elementRef.current) elementRef.current.update(updates);
}, [options, prevOptions]);
React.useLayoutEffect(() => {
return () => {
if (elementRef.current && typeof elementRef.current.destroy === "function") try {
elementRef.current.destroy();
elementRef.current = null;
} catch {}
};
}, []);
return /* @__PURE__ */ React.createElement(React.Fragment, null, !isReady && fallback, /* @__PURE__ */ React.createElement("div", {
id,
style: {
height: isReady ? "unset" : "0px",
visibility: isReady ? "visible" : "hidden"
},
className,
ref: domNode
}));
};
const ServerElement = (props) => {
useElementsOrCheckoutSdkContextWithUseCase(`mounts <${displayName}>`);
const { id, className } = props;
return /* @__PURE__ */ React.createElement("div", {
id,
className
});
};
const Element = isServer ? ServerElement : ClientElement;
Element.displayName = displayName;
Element.__elementType = type;
return Element;
};
const PaymentElement$1 = createElementComponent("payment", typeof window === "undefined");
//#endregion
//#region src/react/billing/useInitializePaymentMethod.tsx
/**
* @internal
*/
function useInitializePaymentMethod(options) {
const { for: forType } = options ?? {};
const organization = useOrganizationBase();
const user = useUserBase();
const resource = forType === "organization" ? organization : user;
const billingEnabled = useBillingIsEnabled(options);
const stableKey = "billing-payment-method-initialize";
const authenticated = true;
const queryKey = useMemo(() => {
return [
stableKey,
authenticated,
{ resourceId: resource?.id },
{}
];
}, [resource?.id]);
const isEnabled = Boolean(resource?.id) && billingEnabled;
useClearQueriesOnSignOut({
isSignedOut: user === null,
authenticated,
stableKeys: stableKey
});
const query = useClerkQuery({
queryKey,
queryFn: async () => {
if (!resource) return;
return resource.initializePaymentMethod({ gateway: "stripe" });
},
enabled: isEnabled,
staleTime: 1e3 * 60,
refetchOnWindowFocus: false,
placeholderData: defineKeepPreviousDataFn(isEnabled)
});
const [queryClient] = useClerkQueryClient();
const initializePaymentMethod = useCallback(async () => {
if (!resource) return;
const result = await resource.initializePaymentMethod({ gateway: "stripe" });
queryClient.setQueryData(queryKey, result);
return result;
}, [
queryClient,
queryKey,
resource
]);
return {
initializedPaymentMethod: query.data ?? void 0,
initializePaymentMethod
};
}
//#endregion
//#region src/react/billing/useStripeClerkLibs.tsx
/**
* @internal
*/
function useStripeClerkLibs() {
const clerk = useClerk();
return useClerkQuery({
queryKey: ["clerk-stripe-sdk"],
queryFn: async () => {
return { loadStripe: await clerk.__internal_loadStripeJs() };
},
staleTime: Infinity,
refetchOnWindowFocus: false,
placeholderData: defineKeepPreviousDataFn(true)
}).data ?? null;
}
//#endregion
//#region src/react/billing/useStripeLoader.tsx
/**
* @internal
*/
function useStripeLoader(options) {
const { stripeClerkLibs, externalGatewayId, stripePublishableKey } = options;
const queryKey = useMemo(() => {
return ["stripe-sdk", {
externalGatewayId,
stripePublishableKey
}];
}, [externalGatewayId, stripePublishableKey]);
const billingEnabled = useBillingIsEnabled({ authenticated: true });
return useClerkQuery({
queryKey,
queryFn: () => {
if (!stripeClerkLibs || !externalGatewayId || !stripePublishableKey) return null;
return stripeClerkLibs.loadStripe(stripePublishableKey, { stripeAccount: externalGatewayId });
},
enabled: Boolean(stripeClerkLibs && externalGatewayId && stripePublishableKey) && billingEnabled,
staleTime: 1e3 * 60,
refetchOnWindowFocus: false,
placeholderData: defineKeepPreviousDataFn(true)
}).data;
}
//#endregion
//#region src/react/billing/payment-element.tsx
const useInternalEnvironment = () => {
return useClerk().__internal_environment;
};
const useLocalization = () => {
const clerk = useClerk();
let locale = "en";
try {
locale = clerk.__internal_getOption("localization")?.locale || "en";
} catch {}
return locale.split("-")[0];
};
const usePaymentSourceUtils = (forResource = "user") => {
const stripeClerkLibs = useStripeClerkLibs();
const environment = useInternalEnvironment();
const { initializedPaymentMethod, initializePaymentMethod } = useInitializePaymentMethod({ for: forResource });
const stripePublishableKey = environment?.commerceSettings.billing.stripePublishableKey ?? void 0;
return {
stripe: useStripeLoader({
stripeClerkLibs,
externalGatewayId: initializedPaymentMethod?.externalGatewayId,
stripePublishableKey
}),
initializePaymentMethod,
externalClientSecret: initializedPaymentMethod?.externalClientSecret,
paymentMethodOrder: initializedPaymentMethod?.paymentMethodOrder
};
};
const [PaymentElementContext, usePaymentElementContext] = createContextAndHook("PaymentElementContext");
const [StripeUtilsContext, useStripeUtilsContext] = createContextAndHook("StripeUtilsContext");
const ValidateStripeUtils = ({ children }) => {
const stripe = useStripe();
const elements = useElements();
return /* @__PURE__ */ React.createElement(StripeUtilsContext.Provider, { value: { value: {
stripe,
elements
} } }, children);
};
const DummyStripeUtils = ({ children }) => {
return /* @__PURE__ */ React.createElement(StripeUtilsContext.Provider, { value: { value: {} } }, children);
};
const PropsProvider = ({ children,...props }) => {
const utils = usePaymentSourceUtils(props.for);
const [isPaymentElementReady, setIsPaymentElementReady] = useState(false);
return /* @__PURE__ */ React.createElement(PaymentElementContext.Provider, { value: { value: {
...props,
...utils,
setIsPaymentElementReady,
isPaymentElementReady
} } }, children);
};
const PaymentElementProvider = ({ children,...props }) => {
return /* @__PURE__ */ React.createElement(PropsProvider, props, /* @__PURE__ */ React.createElement(PaymentElementInternalRoot, null, children));
};
const PaymentElementInternalRoot = (props) => {
const { stripe, externalClientSecret, stripeAppearance } = usePaymentElementContext();
const locale = useLocalization();
if (stripe && externalClientSecret) return /* @__PURE__ */ React.createElement(Elements, {
key: externalClientSecret,
stripe,
options: {
loader: "never",
clientSecret: externalClientSecret,
appearance: { variables: stripeAppearance },
locale
}
}, /* @__PURE__ */ React.createElement(ValidateStripeUtils, null, props.children));
return /* @__PURE__ */ React.createElement(DummyStripeUtils, null, props.children);
};
const PaymentElement = ({ fallback }) => {
const { setIsPaymentElementReady, paymentMethodOrder, checkout, stripe, externalClientSecret, paymentDescription, for: _for } = usePaymentElementContext();
const environment = useInternalEnvironment();
const applePay = useMemo(() => {
if (!checkout || !checkout.totals || !checkout.plan) return;
return { recurringPaymentRequest: {
paymentDescription: paymentDescription || "",
managementURL: _for === "organization" ? environment?.displayConfig.organizationProfileUrl || "" : environment?.displayConfig.userProfileUrl || "",
regularBilling: {
amount: checkout.totals.totalDueNow?.amount || checkout.totals.grandTotal.amount,
label: checkout.plan.name,
recurringPaymentIntervalUnit: checkout.planPeriod === "annual" ? "year" : "month"
}
} };
}, [
checkout,
paymentDescription,
_for,
environment
]);
const options = useMemo(() => {
return {
layout: {
type: "tabs",
defaultCollapsed: false
},
paymentMethodOrder,
applePay
};
}, [applePay, paymentMethodOrder]);
const onReady = useCallback(() => {
setIsPaymentElementReady(true);
}, [setIsPaymentElementReady]);
if (!stripe || !externalClientSecret) return /* @__PURE__ */ React.createElement(React.Fragment, null, fallback);
return /* @__PURE__ */ React.createElement(PaymentElement$1, {
fallback,
onReady,
options
});
};
const throwLibsMissingError = () => {
throw new Error("Clerk: Unable to submit, Stripe libraries are not yet loaded. Be sure to check `isFormReady` before calling `submit`.");
};
const usePaymentElement = () => {
const { isPaymentElementReady, initializePaymentMethod } = usePaymentElementContext();
const { stripe, elements } = useStripeUtilsContext();
const { externalClientSecret } = usePaymentElementContext();
const submit = useCallback(async () => {
if (!stripe || !elements) return throwLibsMissingError();
const { setupIntent, error } = await stripe.confirmSetup({
elements,
confirmParams: { return_url: window.location.href },
redirect: "if_required"
});
if (error) return {
data: null,
error: {
gateway: "stripe",
error: {
code: error.code,
message: error.message,
type: error.type
}
}
};
return {
data: {
gateway: "stripe",
paymentToken: setupIntent.payment_method
},
error: null
};
}, [stripe, elements]);
const reset = useCallback(async () => {
if (!stripe || !elements) return throwLibsMissingError();
await initializePaymentMethod();
}, [
stripe,
elements,
initializePaymentMethod
]);
const isProviderReady = Boolean(stripe && externalClientSecret);
if (!isProviderReady) return {
submit: throwLibsMissingError,
reset: throwLibsMissingError,
isFormReady: false,
provider: void 0,
isProviderReady: false
};
return {
submit,
reset,
isFormReady: isPaymentElementReady,
provider: { name: "stripe" },
isProviderReady
};
};
//#endregion
//#region src/react/PortalProvider.tsx
const [PortalContext, , usePortalContextWithoutGuarantee] = createContextAndHook("PortalProvider");
/**
* UNSAFE_PortalProvider allows you to specify a custom container for Clerk floating UI elements
* (popovers, modals, tooltips, etc.) that use portals.
*
* Only components within this provider will be affected. Components outside the provider
* will continue to use the default document.body for portals.
*
* This is particularly useful when using Clerk components inside external UI libraries
* like Radix Dialog or React Aria Components, where portaled elements need to render
* within the dialog's container to remain interactable.
*
* @example
* ```tsx
* function Example() {
* const containerRef = useRef(null);
* return (
*
* containerRef.current}>
*
*
*
* );
* }
* ```
*/
const UNSAFE_PortalProvider = ({ children, getContainer }) => {
const contextValue = React.useMemo(() => ({ value: { getContainer } }), [getContainer]);
return /* @__PURE__ */ React.createElement(PortalContext.Provider, { value: contextValue }, children);
};
UNSAFE_PortalProvider.displayName = "UNSAFE_PortalProvider";
/**
* Hook to get the current portal root container.
* Returns the getContainer function from context if inside a PortalProvider,
* otherwise returns a function that returns null (default behavior).
*/
const usePortalRoot = () => {
const contextValue = usePortalContextWithoutGuarantee();
if (contextValue && "getContainer" in contextValue && contextValue.getContainer) return contextValue.getContainer;
return () => null;
};
//#endregion
export { ClerkContextProvider, ClerkInstanceContext, InitialStateProvider, OptionsContext, UNSAFE_PortalProvider, __experimental_CheckoutProvider, PaymentElement as __experimental_PaymentElement, PaymentElementProvider as __experimental_PaymentElementProvider, useAPIKeys as __experimental_useAPIKeys, useCheckout as __experimental_useCheckout, usePaymentAttempts as __experimental_usePaymentAttempts, usePaymentElement as __experimental_usePaymentElement, usePaymentMethods as __experimental_usePaymentMethods, usePlans as __experimental_usePlans, useStatements as __experimental_useStatements, useSubscription as __experimental_useSubscription, useClientBase as __internal_useClientBase, useOrganizationBase as __internal_useOrganizationBase, usePaymentAttemptQuery as __internal_usePaymentAttemptQuery, __internal_usePlanDetailsQuery, useSessionBase as __internal_useSessionBase, useStatementQuery as __internal_useStatementQuery, useUserBase as __internal_useUserBase, assertContextExists, createContextAndHook, isDeeplyEqual, useAssertWrappedByClerkProvider, useAttemptToEnableOrganizations, useClerk, useClerkInstanceContext, useDeepEqualMemo, useInitialStateContext, useOptionsContext, useOrganization, useOrganizationCreationDefaults, useOrganizationList, usePortalRoot, useReverification, useSafeLayoutEffect, useSession, useSessionList, useUser };
//# sourceMappingURL=index.mjs.map