Skip to content

Commit 431aa50

Browse files
committed
feat(react,vue,astro): Add ui prop for version metadata
Adds `ui` prop to ClerkProvider for specifying UI version metadata. The bundled UI constructor is not used yet (CDN loading continues). - Add `ui` prop to ClerkProviderProps (version metadata only) - Keep `ctor` in Ui type for future bundling support - Chrome extension continues using internal `clerkUiCtor` prop - Omit `clerkUiCtor` from public ClerkProviderProps type
1 parent fd5cae5 commit 431aa50

9 files changed

Lines changed: 43 additions & 20 deletions

File tree

packages/astro/src/internal/create-clerk-instance.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,16 +109,11 @@ async function getClerkJsEntryChunk<TUi extends Ui = Ui>(options?: AstroClerkCre
109109
}
110110

111111
/**
112-
* Gets the ClerkUI constructor, either from options or by loading the script.
113-
* Returns early if window.__internal_ClerkUiCtor already exists.
112+
* Gets the ClerkUI constructor by loading from CDN.
114113
*/
115114
async function getClerkUiEntryChunk<TUi extends Ui = Ui>(
116115
options?: AstroClerkCreateInstanceParams<TUi>,
117116
): Promise<ClerkUiConstructor> {
118-
if (options?.clerkUiCtor) {
119-
return options.clerkUiCtor;
120-
}
121-
122117
await loadClerkUiScript(options);
123118

124119
if (!window.__internal_ClerkUiCtor) {

packages/astro/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ type AstroClerkIntegrationParams<TUi extends Ui = Ui> = Without<
3636
* The URL that `@clerk/ui` should be hot-loaded from.
3737
*/
3838
clerkUiUrl?: string;
39+
/**
40+
* The Clerk UI bundle to use. When provided with a bundled UI via
41+
* `ui.ctor`, it will be used instead of loading from CDN.
42+
*/
43+
ui?: TUi;
3944
};
4045

4146
type AstroClerkCreateInstanceParams<TUi extends Ui = Ui> = AstroClerkIntegrationParams<TUi> & {

packages/chrome-extension/src/react/ClerkProvider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function ClerkProvider<TUi extends Ui = Ui>(props: ChromeExtensionClerkPr
3434

3535
return (
3636
<ClerkReactProvider
37-
{...rest}
37+
{...(rest as any)}
3838
Clerk={clerkInstance}
3939
clerkUiCtor={ClerkUi}
4040
standardBrowser={!syncHost}

packages/react/src/contexts/ClerkProvider.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { ClerkContextProvider } from './ClerkContextProvider';
99

1010
function ClerkProviderBase<TUi extends Ui>(props: ClerkProviderProps<TUi>) {
1111
const { initialState, children, ...restIsomorphicClerkOptions } = props;
12+
1213
const isomorphicClerkOptions = restIsomorphicClerkOptions as unknown as IsomorphicClerkOptions;
1314

1415
return (

packages/react/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ declare global {
3636
/**
3737
* @interface
3838
*/
39-
export type ClerkProviderProps<TUi extends Ui = Ui> = Omit<IsomorphicClerkOptions, 'appearance'> & {
39+
export type ClerkProviderProps<TUi extends Ui = Ui> = Omit<IsomorphicClerkOptions, 'appearance' | 'clerkUiCtor'> & {
4040
children: React.ReactNode;
4141
/**
4242
* Provide an initial state of the Clerk client during server-side rendering. You don't need to set this value yourself unless you're [developing an SDK](https://clerk.com/docs/guides/development/sdk-development/overview).

packages/shared/src/types/clerk.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2436,7 +2436,15 @@ export type IsomorphicClerkOptions = Without<ClerkOptions, 'isSatellite'> & {
24362436
* This is a structural-only type for the `ui` object that can be passed
24372437
* to Clerk.load() and ClerkProvider
24382438
*/
2439-
ui?: { version: string; url?: string };
2439+
ui?: {
2440+
version: string;
2441+
url?: string;
2442+
/**
2443+
* The Clerk UI constructor. When provided, this will be used instead of
2444+
* loading the UI from CDN. This is useful for bundling the UI with your app.
2445+
*/
2446+
ctor?: ClerkUiConstructor | Promise<ClerkUiConstructor>;
2447+
};
24402448
} & MultiDomainAndOrProxy;
24412449

24422450
export interface LoadedClerk extends Clerk {

packages/ui/src/index.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,17 @@ import type { Appearance } from './internal/appearance';
44
declare const PACKAGE_VERSION: string;
55

66
/**
7-
* Default ui object for Clerk UI components
8-
* Tagged with the internal Appearance type for type-safe appearance prop inference
7+
* UI metadata object for Clerk UI components.
8+
* Pass this to ClerkProvider to specify which UI version to load.
9+
*
10+
* @example
11+
* ```tsx
12+
* import { ui } from '@clerk/ui';
13+
*
14+
* <ClerkProvider ui={ui}>
15+
* ...
16+
* </ClerkProvider>
17+
* ```
918
*/
1019
export const ui = {
1120
version: PACKAGE_VERSION,

packages/ui/src/internal/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { ClerkUiConstructor } from '@clerk/shared/ui';
2+
13
import type { Appearance } from './appearance';
24

35
export type { ComponentControls, MountComponentRenderer } from '../Components';
@@ -26,6 +28,11 @@ export type Ui<A = any> = Tagged<
2628
{
2729
version: string;
2830
url?: string;
31+
/**
32+
* The Clerk UI constructor. When provided, this will be used instead of
33+
* loading the UI from CDN. This is useful for bundling the UI with your app.
34+
*/
35+
ctor?: ClerkUiConstructor | Promise<ClerkUiConstructor>;
2936
/**
3037
* Phantom property for type-level appearance inference
3138
* This property never exists at runtime

packages/vue/src/plugin.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,13 @@ export const clerkPlugin: Plugin<[PluginOptions]> = {
7878
void (async () => {
7979
try {
8080
const clerkPromise = loadClerkJsScript(options);
81-
const clerkUiCtorPromise = pluginOptions.clerkUiCtor
82-
? Promise.resolve(pluginOptions.clerkUiCtor)
83-
: (async () => {
84-
await loadClerkUiScript(options);
85-
if (!window.__internal_ClerkUiCtor) {
86-
throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.');
87-
}
88-
return window.__internal_ClerkUiCtor;
89-
})();
81+
const clerkUiCtorPromise = (async () => {
82+
await loadClerkUiScript(options);
83+
if (!window.__internal_ClerkUiCtor) {
84+
throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.');
85+
}
86+
return window.__internal_ClerkUiCtor;
87+
})();
9088

9189
await clerkPromise;
9290

0 commit comments

Comments
 (0)