@@ -16,9 +16,12 @@ import { queryContactFormGeneratedFieldError, queryContactFormGenericFields } fr
1616
1717export type ContactUiState = 'idle' | 'loading' | 'success' | 'error' | 'validation'
1818
19- export const contactPreviewStates = [ 'loading' , 'success' , 'error' , 'validation' ] as const
19+ export const contactPreviewStates = [ 'loading' , 'success' , 'error' , 'validation' , 'confetti' ] as const
2020
2121type ContactPreviewState = ( typeof contactPreviewStates ) [ number ]
22+ type ContactPreviewMode = 'confetti'
23+
24+ const contactPreviewModeAttribute = 'data-contact-preview-mode'
2225
2326interface SubmissionControllers {
2427 labelController : LabelController
@@ -48,6 +51,26 @@ const setContactState = (
4851 rootElement ?. setAttribute ( 'data-contact-state' , state )
4952}
5053
54+ const setContactPreviewMode = (
55+ rootElement : HTMLElement | null | undefined ,
56+ previewMode ?: ContactPreviewMode
57+ ) : void => {
58+ if ( ! rootElement ) {
59+ return
60+ }
61+
62+ if ( previewMode ) {
63+ rootElement . setAttribute ( contactPreviewModeAttribute , previewMode )
64+ return
65+ }
66+
67+ rootElement . removeAttribute ( contactPreviewModeAttribute )
68+ }
69+
70+ const isConfettiPreviewMode = ( rootElement : HTMLElement | null | undefined ) : boolean => {
71+ return rootElement ?. getAttribute ( contactPreviewModeAttribute ) === 'confetti'
72+ }
73+
5174const showSuccessMessage = ( elements : ContactFormElements ) : void => {
5275 elements . messages . style . display = 'block'
5376 elements . successMessage . classList . remove ( 'hidden' )
@@ -62,6 +85,15 @@ const showErrorMessage = (elements: ContactFormElements, message: string): void
6285 elements . errorText . textContent = message
6386}
6487
88+ const fireConfetti = ( elements : ContactFormElements ) : void => {
89+ elements . submitBtn . dispatchEvent (
90+ new CustomEvent ( 'confetti:fire' , {
91+ bubbles : true ,
92+ composed : true ,
93+ } )
94+ )
95+ }
96+
6597const setLoading = ( elements : ContactFormElements , loading : boolean ) : void => {
6698 elements . submitBtn . disabled = loading
6799
@@ -114,6 +146,7 @@ export const applyContactPreviewState = (
114146 }
115147) : void => {
116148 resetSubmissionFeedback ( elements )
149+ setContactPreviewMode ( options . rootElement , options . state === 'confetti' ? 'confetti' : undefined )
117150
118151 switch ( options . state ) {
119152 case 'loading' :
@@ -139,9 +172,29 @@ export const applyContactPreviewState = (
139172 showErrorMessage ( elements , 'Please correct the highlighted fields and try again.' )
140173 setContactState ( options . rootElement , 'validation' )
141174 return
175+
176+ case 'confetti' :
177+ setContactState ( options . rootElement , 'idle' )
178+ return
142179 }
143180}
144181
182+ const runConfettiPreviewSequence = async (
183+ elements : ContactFormElements ,
184+ rootElement : HTMLElement | null | undefined
185+ ) : Promise < void > => {
186+ hideErrorBanner ( elements . formErrorBanner )
187+ hideMessages ( elements )
188+ setLoading ( elements , true )
189+ setContactState ( rootElement , 'loading' )
190+
191+ await Promise . resolve ( )
192+
193+ showSuccessMessage ( elements )
194+ setContactState ( rootElement , 'success' )
195+ fireConfetti ( elements )
196+ }
197+
145198const runFieldValidations = ( elements : ContactFormElements ) : boolean => {
146199 const validations = [
147200 validateEmailField ( elements . fields . email ) ,
@@ -205,6 +258,13 @@ export const initFormSubmission = (
205258 addScriptBreadcrumb ( context )
206259
207260 try {
261+ if ( isConfettiPreviewMode ( controllers . rootElement ) ) {
262+ resetSubmissionFeedback ( elements )
263+ await runConfettiPreviewSequence ( elements , controllers . rootElement )
264+ setLoading ( elements , false )
265+ return
266+ }
267+
208268 Object . values ( elements . fields ) . forEach ( clearFieldFeedback )
209269 const isValid = runFieldValidations ( elements )
210270
@@ -240,12 +300,7 @@ export const initFormSubmission = (
240300 showSuccessMessage ( elements )
241301 setContactState ( controllers . rootElement , 'success' )
242302
243- elements . submitBtn . dispatchEvent (
244- new CustomEvent ( 'confetti:fire' , {
245- bubbles : true ,
246- composed : true ,
247- } )
248- )
303+ fireConfetti ( elements )
249304
250305 resetFormState ( elements , controllers )
251306 } catch ( error ) {
0 commit comments