@@ -4,7 +4,7 @@ import type { __internal_EnableOrganizationsPromptProps, EnableEnvironmentSettin
44import type { SerializedStyles } from '@emotion/react' ;
55// eslint-disable-next-line no-restricted-imports
66import { css , type Theme } from '@emotion/react' ;
7- import { forwardRef , useId , useMemo , useRef , useState } from 'react' ;
7+ import { forwardRef , useId , useLayoutEffect , useMemo , useRef , useState } from 'react' ;
88
99import { useEnvironment } from '@/ui/contexts' ;
1010import { Modal } from '@/ui/elements/Modal' ;
@@ -122,128 +122,7 @@ const EnableOrganizationsPromptInternal = ({
122122 gap : t . sizes . $2 ,
123123 } ) }
124124 >
125- < div
126- css = { css `
127- perspective : 1000px ;
128- position : relative;
129- width : 1.25rem ;
130- height : 1.25rem ;
131- transform-style : preserve-3d;
132- transition : transform 0.6s ease-in-out;
133- transform : ${ isEnabled ? 'rotateY(180deg)' : 'rotateY(0)' } ;
134- animation : ${ ! isEnabled ? 'coinFlipAnimation 6s infinite linear' : 'none' } ;
135-
136- @keyframes coinFlipAnimation {
137- 0% ,
138- 55% {
139- transform : rotateY (0 );
140- }
141- 60% ,
142- 95% {
143- transform : rotateY (180deg );
144- }
145- 100% {
146- transform : rotateY (0 );
147- }
148- }
149-
150- @media (prefers-reduced-motion : reduce) {
151- transition : none;
152- animation : none;
153- transform : ${ isEnabled ? 'rotateY(180deg)' : 'rotateY(0)' } ;
154- }
155- ` }
156- >
157- { isEnabled ? (
158- < span
159- aria-hidden
160- css = { css `
161- position : absolute;
162- width : 100% ;
163- height : 100% ;
164- backface-visibility : hidden;
165- transform : rotateY (180deg );
166- display : flex;
167- align-items : center;
168- justify-content : center;
169- ` }
170- >
171- < PromptSuccessIcon
172- css = { css `
173- width : 1.25rem ;
174- height : 1.25rem ;
175- ` }
176- />
177- </ span >
178- ) : (
179- < >
180- < span
181- className = 'coin-flip-front'
182- aria-hidden
183- css = { css `
184- position : absolute;
185- width : 100% ;
186- height : 100% ;
187- backface-visibility : hidden;
188- display : flex;
189- align-items : center;
190- justify-content : center;
191- ` }
192- >
193- < ClerkLogoIcon />
194- </ span >
195-
196- < span
197- className = 'coin-flip-back'
198- aria-hidden
199- css = { css `
200- position : absolute;
201- width : 100% ;
202- height : 100% ;
203- backface-visibility : hidden;
204- transform : rotateY (180deg );
205- display : flex;
206- align-items : center;
207- justify-content : center;
208- ` }
209- >
210- < svg
211- css = { css `
212- width : 1.25rem ;
213- height : 1.25rem ;
214- ` }
215- viewBox = '0 0 20 20'
216- fill = 'none'
217- xmlns = 'http://www.w3.org/2000/svg'
218- >
219- < path
220- opacity = '0.2'
221- d = 'M17.25 10C17.25 14.0041 14.0041 17.25 10 17.25C5.99594 17.25 2.75 14.0041 2.75 10C2.75 5.99594 5.99594 2.75 10 2.75C14.0041 2.75 17.25 5.99594 17.25 10Z'
222- fill = '#EAB308'
223- />
224- < path
225- fillRule = 'evenodd'
226- clipRule = 'evenodd'
227- d = 'M10 3.5C6.41015 3.5 3.5 6.41015 3.5 10C3.5 13.5899 6.41015 16.5 10 16.5C13.5899 16.5 16.5 13.5899 16.5 10C16.5 6.41015 13.5899 3.5 10 3.5ZM2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10Z'
228- fill = '#EAB308'
229- />
230- < path
231- fillRule = 'evenodd'
232- clipRule = 'evenodd'
233- d = 'M10 6C10.5523 6 11 6.44772 11 7V9C11 9.55228 10.5523 10 10 10C9.44772 10 9 9.55228 9 9V7C9 6.44772 9.44772 6 10 6Z'
234- fill = '#EAB308'
235- />
236- < path
237- fillRule = 'evenodd'
238- clipRule = 'evenodd'
239- d = 'M10 12C10.5523 12 11 12.4477 11 13V13.01C11 13.5623 10.5523 14.01 10 14.01C9.44772 14.01 9 13.5623 9 13.01V13C9 12.4477 9.44772 12 10 12Z'
240- fill = '#EAB308'
241- />
242- </ svg >
243- </ span >
244- </ >
245- ) }
246- </ div >
125+ < CoinFlip isEnabled = { isEnabled } />
247126
248127 < h1
249128 css = { [
@@ -679,3 +558,144 @@ const Link = forwardRef<HTMLAnchorElement, React.ComponentProps<'a'> & { css?: S
679558 ) ;
680559 } ,
681560) ;
561+
562+ const CoinFlip = ( { isEnabled } : { isEnabled : boolean } ) => {
563+ const [ rotation , setRotation ] = useState ( 0 ) ;
564+
565+ useLayoutEffect ( ( ) => {
566+ if ( isEnabled ) {
567+ setRotation ( r => ( r === 0 ? 180 : 0 ) ) ;
568+ return ;
569+ }
570+
571+ const interval = setInterval ( ( ) => {
572+ setRotation ( r => ( r === 0 ? 180 : 0 ) ) ;
573+ } , 2000 ) ;
574+
575+ return ( ) => clearInterval ( interval ) ;
576+ } , [ isEnabled ] ) ;
577+
578+ let frontFaceType : 'idle' | 'success' = 'idle' ;
579+ let backFaceType : 'warning' | 'success' = 'warning' ;
580+
581+ if ( isEnabled ) {
582+ if ( rotation === 0 ) {
583+ frontFaceType = 'success' ;
584+ backFaceType = 'warning' ;
585+ } else {
586+ backFaceType = 'success' ;
587+ frontFaceType = 'idle' ;
588+ }
589+ }
590+
591+ const renderContent = ( type : 'idle' | 'warning' | 'success' ) => {
592+ switch ( type ) {
593+ case 'idle' :
594+ return < ClerkLogoIcon /> ;
595+ case 'success' :
596+ return (
597+ < PromptSuccessIcon
598+ css = { css `
599+ width : 1.25rem ;
600+ height : 1.25rem ;
601+ ` }
602+ />
603+ ) ;
604+ case 'warning' :
605+ return (
606+ < svg
607+ css = { css `
608+ width : 1.25rem ;
609+ height : 1.25rem ;
610+ ` }
611+ viewBox = '0 0 20 20'
612+ fill = 'none'
613+ xmlns = 'http://www.w3.org/2000/svg'
614+ >
615+ < path
616+ opacity = '0.2'
617+ d = 'M17.25 10C17.25 14.0041 14.0041 17.25 10 17.25C5.99594 17.25 2.75 14.0041 2.75 10C2.75 5.99594 5.99594 2.75 10 2.75C14.0041 2.75 17.25 5.99594 17.25 10Z'
618+ fill = '#EAB308'
619+ />
620+ < path
621+ fillRule = 'evenodd'
622+ clipRule = 'evenodd'
623+ d = 'M10 3.5C6.41015 3.5 3.5 6.41015 3.5 10C3.5 13.5899 6.41015 16.5 10 16.5C13.5899 16.5 16.5 13.5899 16.5 10C16.5 6.41015 13.5899 3.5 10 3.5ZM2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10Z'
624+ fill = '#EAB308'
625+ />
626+ < path
627+ fillRule = 'evenodd'
628+ clipRule = 'evenodd'
629+ d = 'M10 6C10.5523 6 11 6.44772 11 7V9C11 9.55228 10.5523 10 10 10C9.44772 10 9 9.55228 9 9V7C9 6.44772 9.44772 6 10 6Z'
630+ fill = '#EAB308'
631+ />
632+ < path
633+ fillRule = 'evenodd'
634+ clipRule = 'evenodd'
635+ d = 'M10 12C10.5523 12 11 12.4477 11 13V13.01C11 13.5623 10.5523 14.01 10 14.01C9.44772 14.01 9 13.5623 9 13.01V13C9 12.4477 9.44772 12 10 12Z'
636+ fill = '#EAB308'
637+ />
638+ </ svg >
639+ ) ;
640+ }
641+ } ;
642+
643+ return (
644+ < div
645+ css = { css `
646+ perspective : 1000px ;
647+ width : 1.25rem ;
648+ height : 1.25rem ;
649+ ` }
650+ >
651+ < div
652+ css = { css `
653+ position : relative;
654+ width : 100% ;
655+ height : 100% ;
656+ transform-style : preserve-3d;
657+ transition : transform 0.6s ease-in-out;
658+ transform : rotateY (${ rotation } deg);
659+
660+ @media (prefers-reduced-motion : reduce) {
661+ transition : none;
662+ }
663+ ` }
664+ >
665+ < span
666+ aria-hidden
667+ css = { css `
668+ position : absolute;
669+ width : 100% ;
670+ height : 100% ;
671+ backface-visibility : hidden;
672+ display : flex;
673+ align-items : center;
674+ justify-content : center;
675+ -webkit-font-smoothing : antialiased;
676+ transform : rotateY (0deg );
677+ ` }
678+ >
679+ { renderContent ( frontFaceType ) }
680+ </ span >
681+
682+ < span
683+ aria-hidden
684+ css = { css `
685+ position : absolute;
686+ width : 100% ;
687+ height : 100% ;
688+ backface-visibility : hidden;
689+ transform : rotateY (180deg );
690+ display : flex;
691+ align-items : center;
692+ justify-content : center;
693+ -webkit-font-smoothing : antialiased;
694+ ` }
695+ >
696+ { renderContent ( backFaceType ) }
697+ </ span >
698+ </ div >
699+ </ div >
700+ ) ;
701+ } ;
0 commit comments