@@ -6,7 +6,7 @@ import * as React from 'react';
66import { useEffect , useMemo , useState } from 'react' ;
77import { createPortal } from 'react-dom' ;
88
9- import { Flex , Link } from '../../../customizables' ;
9+ import { Flex } from '../../../customizables' ;
1010import { Portal } from '../../../elements/Portal' ;
1111import { InternalThemeProvider } from '../../../styledSystem' ;
1212import {
@@ -55,6 +55,10 @@ const KeylessPromptInternal = (_props: KeylessPromptProps) => {
5555 const success = typeof _props . onDismiss === 'function' && claimed ;
5656 const appName = environment . displayConfig . applicationName ;
5757
58+ // Mock state to 'idle' for now
59+ const currentState : keyof typeof STATES = 'idle' ;
60+ const content = getContent ( currentState ) ;
61+
5862 const isForcedExpanded = claimed || success || isExpanded ;
5963 const claimUrlToDashboard = useMemo ( ( ) => {
6064 if ( claimed ) {
@@ -245,10 +249,8 @@ const KeylessPromptInternal = (_props: KeylessPromptProps) => {
245249 ) }
246250
247251 < p
248- data-text = 'Clerk is in keyless mode'
249- aria-label = {
250- success ? 'Claim completed' : claimed ? 'Missing environment keys' : 'Clerk is in keyless mode'
251- }
252+ data-text = { content . title }
253+ aria-label = { content . ariaLabel }
252254 css = { css `
253255 ${ basePromptElementStyles } ;
254256 color : # d9d9d9 ;
@@ -258,7 +260,7 @@ const KeylessPromptInternal = (_props: KeylessPromptProps) => {
258260 cursor : pointer;
259261 ` }
260262 >
261- { success ? 'Claim completed' : claimed ? 'Missing environment keys' : 'Clerk is in keyless mode' }
263+ { content . title }
262264 </ p >
263265 </ Flex >
264266
@@ -334,107 +336,7 @@ const KeylessPromptInternal = (_props: KeylessPromptProps) => {
334336 }
335337 ` }
336338 >
337- { success ? (
338- < p
339- css = { css `
340- ${ basePromptElementStyles } ;
341- color : # b4b4b4 ;
342- font- size: 0.8125rem;
343- font- weight: 400;
344- line-height: 1rem;
345- ` }
346- >
347- Your application{ ' ' }
348- < span
349- css = { css `
350- ${ basePromptElementStyles } ;
351- dis play: inline-block;
352- white-space: nowrap;
353- overflow: hidden;
354- text- overflow: ellipsis ;
355- max- width: 8.125rem;
356- vertical- align: botto m;
357- font- size: 0.8125rem;
358- font- weight: 500;
359- color : # d5d5d5 ;
360- ` }
361- >
362- { appName }
363- </ span > { ' ' }
364- has been claimed. Configure settings from the{ ' ' }
365- < Link
366- isExternal
367- aria-label = 'Go to Dashboard to configure settings'
368- href = { instanceUrlToDashboard }
369- sx = { t => ( {
370- color : t . colors . $whiteAlpha600 ,
371- textDecoration : 'underline solid' ,
372- transition : `${ t . transitionTiming . $common } ${ t . transitionDuration . $fast } ` ,
373- ':hover' : {
374- color : t . colors . $whiteAlpha800 ,
375- } ,
376- } ) }
377- >
378- Clerk Dashboard
379- </ Link >
380- </ p >
381- ) : claimed ? (
382- < p
383- css = { css `
384- ${ basePromptElementStyles } ;
385- color : # b4b4b4 ;
386- font- size: 0.8125rem;
387- font- weight: 400;
388- line-height: 1rem;
389- ` }
390- >
391- You claimed this application but haven't set keys in your environment. Get them from the Clerk
392- Dashboard.
393- </ p >
394- ) : isSignedIn ? (
395- < p
396- css = { css `
397- ${ basePromptElementStyles } ;
398- color : # b4b4b4 ;
399- font- size: 0.8125rem;
400- font- weight: 400;
401- line-height: 1rem;
402- ` }
403- >
404- < span >
405- You've created your first user! Link this application to your Clerk account to explore the
406- Dashboard.
407- </ span >
408- </ p >
409- ) : (
410- < >
411- < p
412- css = { css `
413- ${ basePromptElementStyles } ;
414- color : # b4b4b4 ;
415- font- size: 0.8125rem;
416- font- weight: 400;
417- line-height: 1rem;
418- text- wrap: pretty;
419- ` }
420- >
421- Temporary API keys are enabled so you can get started immediately.
422- </ p >
423- < p
424- css = { css `
425- ${ basePromptElementStyles } ;
426- color : # b4b4b4 ;
427- font- size: 0.8125rem;
428- font- weight: 400;
429- line-height: 1rem;
430- text- wrap: pretty;
431- ` }
432- >
433- Claim this application to access the Clerk Dashboard where you can manage auth settings and explore
434- more Clerk features.
435- </ p >
436- </ >
437- ) }
339+ { renderDescription ( content . description ) }
438340 </ div >
439341 </ div >
440342
@@ -502,7 +404,7 @@ const KeylessPromptInternal = (_props: KeylessPromptProps) => {
502404 }
503405 ` }
504406 >
505- { claimed ? 'Get API keys' : 'Claim application' }
407+ { content . buttonText }
506408 </ a >
507409 </ Flex >
508410 ) ) }
@@ -572,9 +474,90 @@ const CSS_RESET = css`
572474
573475const getDuration = ( isOpen : boolean ) => ( isOpen ? DURATION_OPEN : DURATION_CLOSE ) ;
574476
477+ type STATES = 'idle' | 'userCreated' | 'completed' ;
478+
479+ /**
480+ * Content structure for each state in the KeylessPrompt component.
481+ * Each state maps to UI content including title, description, and button text.
482+ */
483+ type ContentItem = {
484+ title : string ;
485+ description : React . ReactNode | ( ( ...args : any [ ] ) => React . ReactNode ) ;
486+ buttonText : string ;
487+ } ;
488+
489+ const CONTENT : Record < STATES , ContentItem > = {
490+ idle : {
491+ title : 'Configure your application' ,
492+ description : (
493+ < >
494+ < p > Temporary API keys are enabled so you can get started immediately.</ p >
495+ < ul >
496+ { [ 'Add SSO connections (eg. GitHub)' , 'Set up B2B authentication' , 'Enable MFA' ] . map ( item => (
497+ < li key = { item } > { item } </ li >
498+ ) ) }
499+ </ ul >
500+ < p > Access the dashboard to customize auth settings and explore Clerk features.</ p >
501+ </ >
502+ ) ,
503+ buttonText : 'Confirgure your application' ,
504+ } ,
505+ userCreated : {
506+ title : 'Clerk is in keyless mode' ,
507+ description : < p > TODO</ p > ,
508+ buttonText : 'Claim application' ,
509+ } ,
510+ completed : {
511+ title : 'Claim completed' ,
512+ description : ( _appName : string , _instanceUrlToDashboard : string ) => < p > TODO</ p > ,
513+ buttonText : 'TODO' ,
514+ } ,
515+ } ;
516+
517+ /**
518+ * Determines the current state based on component props and environment.
519+ * You can modify this logic to match your state management needs.
520+ */
521+ const getCurrentState = ( claimed : boolean , success : boolean , isSignedIn : boolean ) : STATES => {
522+ if ( success ) {
523+ return 'completed' ;
524+ }
525+ if ( claimed ) {
526+ return 'completed' ;
527+ }
528+ if ( isSignedIn ) {
529+ return 'userCreated' ;
530+ }
531+ return 'idle' ;
532+ } ;
533+
534+ /**
535+ * Gets the content object for a given state.
536+ */
537+ const getContent = ( state : STATES ) => CONTENT [ state ] ;
538+
539+ /**
540+ * Renders the description content, handling both ReactNode and function cases.
541+ * For function descriptions, pass the required parameters.
542+ */
543+ const renderDescription = ( description : ContentItem [ 'description' ] , ...args : any [ ] ) : React . ReactNode => {
544+ if ( typeof description === 'function' ) {
545+ return description ( ...args ) ;
546+ }
547+ return description ;
548+ } ;
549+
575550function Keyless ( ) {
576551 const id = React . useId ( ) ;
552+
553+ const claimed = false ;
554+ const success = false ;
555+ const isSignedIn = false ;
556+ const appName = 'My App' ;
557+ const instanceUrlToDashboard = 'https://dashboard.clerk.com' ;
558+
577559 const [ isOpen , setIsOpen ] = useState ( false ) ;
560+ const [ currentState , setCurrentState ] = useState < STATES > ( getCurrentState ( claimed , success , isSignedIn ) ) ;
578561 return (
579562 < div
580563 data-expanded = { isOpen }
@@ -673,7 +656,7 @@ function Keyless() {
673656 white-space: nowrap;
674657 ` }
675658 >
676- Configure your application
659+ { getContent ( currentState ) . title }
677660 </ span >
678661 < svg
679662 css = { css `
@@ -723,60 +706,33 @@ function Keyless() {
723706 padding- block- end: 0.75rem;
724707 opacity: ${ isOpen ? 1 : 0 } ;
725708 transition: opacity ${ getDuration ( isOpen ) } ${ EASE_BEZIER } ;
726- ` }
727- >
728- < p
729- css = { css `
709+ d is play : flex;
710+ flex - direction : column;
711+ gap : 0.5rem;
712+ & p {
730713 ${ CSS_RESET } ;
731714 color : # b4b4b4 ;
732715 font- size: 0.8125rem;
733716 font- weight: 400;
734717 line-height: 1rem;
735- text- box- trim: trim- start;
736- ` }
737- >
738- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dignissimos qui laboriosam sit fugiat, ipsam
739- animi minima neque alias mollitia expedita.
740- </ p >
741- < ul
742- css = { css `
718+ text- wrap: pretty;
719+ }
720+ & ul {
743721 ${ CSS_RESET } ;
744- margin- to p: 0.5rem;
745- padding- inline-start: 1rem;
746722 lis t- style: dis c;
747- ` }
748- >
749- { [ 'Add SSO connections (eg. GitHub)' , 'Set up B2B authentication' , 'Enable MFA' ] . map ( item => (
750- < li
751- key = { item }
752- css = { css `
753- ${ CSS_RESET } ;
754- color : # b4b4b4 ;
755- font- size: 0.8125rem;
756- font- weight: 400;
757- line-height: 1rem;
758- & : not (: first-child ) {
759- margin-top : 0.25rem ;
760- }
761- ` }
762- >
763- { item }
764- </ li >
765- ) ) }
766- </ ul >
767- < p
768- css = { css `
723+ padding- left: 1rem;
724+ }
725+ & li {
769726 ${ CSS_RESET } ;
770- margin- to p: 0.5rem;
771727 color : # b4b4b4 ;
772728 font- size: 0.8125rem;
773729 font- weight: 400;
774730 line-height: 1rem;
775- ` }
776- >
777- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dignissimos qui laboriosam sit fugiat, ipsam
778- animi minima neque alias mollitia expedita.
779- </ p >
731+ text - wrap : pretty;
732+ }
733+ ` }
734+ >
735+ { renderDescription ( getContent ( currentState ) . description , appName , instanceUrlToDashboard ) }
780736
781737 < a
782738 href = 'https://clerk.com/dashboard'
@@ -819,7 +775,7 @@ function Keyless() {
819775 }
820776 ` }
821777 >
822- Configure your application
778+ { getContent ( currentState ) . buttonText }
823779 </ a >
824780 </ div >
825781 </ div >
0 commit comments