@forms.expert/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Form field types
3
+ */
4
+ type BasicFieldType = 'text' | 'email' | 'number' | 'textarea' | 'select' | 'checkbox' | 'file' | 'date' | 'hidden';
5
+ type InteractiveFieldType = 'radio' | 'multiselect' | 'rating' | 'scale' | 'toggle' | 'ranking' | 'imageChoice' | 'phone' | 'url' | 'password' | 'richText' | 'slider' | 'currency' | 'time' | 'datetime' | 'dateRange' | 'address' | 'name' | 'dropdown' | 'colorPicker' | 'location' | 'opinionScale' | 'consent';
6
+ type LayoutFieldType = 'heading' | 'divider' | 'paragraph';
7
+ type FormFieldType = BasicFieldType | InteractiveFieldType | LayoutFieldType;
8
+ interface FormFieldOption {
9
+ label: string;
10
+ value: string;
11
+ imageUrl?: string;
12
+ }
13
+ /**
14
+ * Form field definition
15
+ */
16
+ interface FormField {
17
+ name: string;
18
+ type: FormFieldType;
19
+ label?: string;
20
+ placeholder?: string;
21
+ required?: boolean;
22
+ options?: string[] | FormFieldOption[];
23
+ defaultValue?: unknown;
24
+ maxFileSize?: number;
25
+ allowedMimeTypes?: string[];
26
+ multiple?: boolean;
27
+ min?: number;
28
+ max?: number;
29
+ step?: number;
30
+ ratingMax?: number;
31
+ lowLabel?: string;
32
+ highLabel?: string;
33
+ defaultCountryCode?: string;
34
+ currencyCode?: string;
35
+ currencySymbol?: string;
36
+ addressFields?: ('street' | 'street2' | 'city' | 'state' | 'zip' | 'country')[];
37
+ nameFields?: ('prefix' | 'first' | 'middle' | 'last' | 'suffix')[];
38
+ content?: string;
39
+ consentText?: string;
40
+ consentUrl?: string;
41
+ maxLength?: number;
42
+ stepId?: string;
43
+ visibleWhen?: {
44
+ field: string;
45
+ operator: 'eq' | 'neq' | 'contains' | 'gt' | 'lt';
46
+ value: unknown;
47
+ };
48
+ }
49
+ /**
50
+ * Form styling configuration
51
+ */
52
+ interface FormStyling {
53
+ theme: 'light' | 'dark' | 'system';
54
+ primaryColor: string;
55
+ backgroundColor: string;
56
+ textColor: string;
57
+ borderRadius: 'none' | 'sm' | 'md' | 'lg';
58
+ fontSize: 'sm' | 'md' | 'lg';
59
+ buttonStyle: 'filled' | 'outline';
60
+ labelPosition: 'top' | 'left' | 'floating';
61
+ customCss?: string;
62
+ }
63
+ /**
64
+ * Form schema
65
+ */
66
+ interface FormSchema {
67
+ fields: FormField[];
68
+ styling?: FormStyling;
69
+ }
70
+ /**
71
+ * Validation error
72
+ */
73
+ interface ValidationError {
74
+ field: string;
75
+ message: string;
76
+ }
77
+ /**
78
+ * Submission response from API
79
+ */
80
+ interface SubmissionResponse {
81
+ success: boolean;
82
+ submissionId: string;
83
+ message: string;
84
+ }
85
+ /**
86
+ * SDK configuration
87
+ */
88
+ interface FormsSDKConfig {
89
+ apiKey: string;
90
+ resourceId: string;
91
+ baseUrl?: string;
92
+ }
93
+
94
+ declare function generateFormStyles(styling?: FormStyling): string;
95
+
96
+ /**
97
+ * Create a form field element
98
+ */
99
+ declare function renderField(field: FormField, value: unknown, error?: string): HTMLElement;
100
+ /**
101
+ * Render the entire form
102
+ */
103
+ declare function renderForm(schema: FormSchema, values?: Record<string, unknown>, errors?: Record<string, string>, options?: {
104
+ honeypot?: boolean;
105
+ showBranding?: boolean;
106
+ brandingText?: string;
107
+ brandingUrl?: string;
108
+ submitText?: string;
109
+ isLoading?: boolean;
110
+ }): HTMLFormElement;
111
+ /**
112
+ * Render success message
113
+ */
114
+ declare function renderSuccess(message: string): HTMLElement;
115
+ /**
116
+ * Convert validation errors array to record
117
+ */
118
+ declare function errorsToRecord(errors: ValidationError[]): Record<string, string>;
119
+
120
+ interface FormWidgetOptions {
121
+ /** Target element or selector */
122
+ target: string | HTMLElement;
123
+ /** Form slug */
124
+ slug: string;
125
+ /** Track form views for analytics (completion rate). Default: false */
126
+ trackViews?: boolean;
127
+ /** Custom submit button text */
128
+ submitText?: string;
129
+ /** Success callback */
130
+ onSuccess?: (response: SubmissionResponse) => void;
131
+ /** Error callback */
132
+ onError?: (error: Error) => void;
133
+ /** Validation error callback */
134
+ onValidationError?: (errors: ValidationError[]) => void;
135
+ /** Reset form after submission */
136
+ resetOnSuccess?: boolean;
137
+ /** Redirect after success (overrides form config) */
138
+ redirectUrl?: string;
139
+ }
140
+ /**
141
+ * Form widget for embedding forms
142
+ */
143
+ declare class FormWidget {
144
+ private sdk;
145
+ private container;
146
+ private config;
147
+ private values;
148
+ private errors;
149
+ private isLoading;
150
+ private isSubmitted;
151
+ private options;
152
+ private styleEl;
153
+ constructor(sdkConfig: FormsSDKConfig, options: FormWidgetOptions);
154
+ /**
155
+ * Initialize and render the form
156
+ */
157
+ init(): Promise<void>;
158
+ /**
159
+ * Inject CSS styles
160
+ */
161
+ private injectStyles;
162
+ /**
163
+ * Render the form
164
+ */
165
+ private render;
166
+ /**
167
+ * Handle form submission
168
+ */
169
+ private handleSubmit;
170
+ /**
171
+ * Reset form to initial state
172
+ */
173
+ reset(): void;
174
+ /**
175
+ * Render error message
176
+ */
177
+ private renderError;
178
+ /**
179
+ * Destroy widget
180
+ */
181
+ destroy(): void;
182
+ }
183
+ /**
184
+ * Auto-initialize forms on page load
185
+ */
186
+ declare function autoInit(): void;
187
+
188
+ export { FormWidget, type FormWidgetOptions, autoInit, errorsToRecord, generateFormStyles, renderField, renderForm, renderSuccess };
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Form field types
3
+ */
4
+ type BasicFieldType = 'text' | 'email' | 'number' | 'textarea' | 'select' | 'checkbox' | 'file' | 'date' | 'hidden';
5
+ type InteractiveFieldType = 'radio' | 'multiselect' | 'rating' | 'scale' | 'toggle' | 'ranking' | 'imageChoice' | 'phone' | 'url' | 'password' | 'richText' | 'slider' | 'currency' | 'time' | 'datetime' | 'dateRange' | 'address' | 'name' | 'dropdown' | 'colorPicker' | 'location' | 'opinionScale' | 'consent';
6
+ type LayoutFieldType = 'heading' | 'divider' | 'paragraph';
7
+ type FormFieldType = BasicFieldType | InteractiveFieldType | LayoutFieldType;
8
+ interface FormFieldOption {
9
+ label: string;
10
+ value: string;
11
+ imageUrl?: string;
12
+ }
13
+ /**
14
+ * Form field definition
15
+ */
16
+ interface FormField {
17
+ name: string;
18
+ type: FormFieldType;
19
+ label?: string;
20
+ placeholder?: string;
21
+ required?: boolean;
22
+ options?: string[] | FormFieldOption[];
23
+ defaultValue?: unknown;
24
+ maxFileSize?: number;
25
+ allowedMimeTypes?: string[];
26
+ multiple?: boolean;
27
+ min?: number;
28
+ max?: number;
29
+ step?: number;
30
+ ratingMax?: number;
31
+ lowLabel?: string;
32
+ highLabel?: string;
33
+ defaultCountryCode?: string;
34
+ currencyCode?: string;
35
+ currencySymbol?: string;
36
+ addressFields?: ('street' | 'street2' | 'city' | 'state' | 'zip' | 'country')[];
37
+ nameFields?: ('prefix' | 'first' | 'middle' | 'last' | 'suffix')[];
38
+ content?: string;
39
+ consentText?: string;
40
+ consentUrl?: string;
41
+ maxLength?: number;
42
+ stepId?: string;
43
+ visibleWhen?: {
44
+ field: string;
45
+ operator: 'eq' | 'neq' | 'contains' | 'gt' | 'lt';
46
+ value: unknown;
47
+ };
48
+ }
49
+ /**
50
+ * Form styling configuration
51
+ */
52
+ interface FormStyling {
53
+ theme: 'light' | 'dark' | 'system';
54
+ primaryColor: string;
55
+ backgroundColor: string;
56
+ textColor: string;
57
+ borderRadius: 'none' | 'sm' | 'md' | 'lg';
58
+ fontSize: 'sm' | 'md' | 'lg';
59
+ buttonStyle: 'filled' | 'outline';
60
+ labelPosition: 'top' | 'left' | 'floating';
61
+ customCss?: string;
62
+ }
63
+ /**
64
+ * Form schema
65
+ */
66
+ interface FormSchema {
67
+ fields: FormField[];
68
+ styling?: FormStyling;
69
+ }
70
+ /**
71
+ * Validation error
72
+ */
73
+ interface ValidationError {
74
+ field: string;
75
+ message: string;
76
+ }
77
+ /**
78
+ * Submission response from API
79
+ */
80
+ interface SubmissionResponse {
81
+ success: boolean;
82
+ submissionId: string;
83
+ message: string;
84
+ }
85
+ /**
86
+ * SDK configuration
87
+ */
88
+ interface FormsSDKConfig {
89
+ apiKey: string;
90
+ resourceId: string;
91
+ baseUrl?: string;
92
+ }
93
+
94
+ declare function generateFormStyles(styling?: FormStyling): string;
95
+
96
+ /**
97
+ * Create a form field element
98
+ */
99
+ declare function renderField(field: FormField, value: unknown, error?: string): HTMLElement;
100
+ /**
101
+ * Render the entire form
102
+ */
103
+ declare function renderForm(schema: FormSchema, values?: Record<string, unknown>, errors?: Record<string, string>, options?: {
104
+ honeypot?: boolean;
105
+ showBranding?: boolean;
106
+ brandingText?: string;
107
+ brandingUrl?: string;
108
+ submitText?: string;
109
+ isLoading?: boolean;
110
+ }): HTMLFormElement;
111
+ /**
112
+ * Render success message
113
+ */
114
+ declare function renderSuccess(message: string): HTMLElement;
115
+ /**
116
+ * Convert validation errors array to record
117
+ */
118
+ declare function errorsToRecord(errors: ValidationError[]): Record<string, string>;
119
+
120
+ interface FormWidgetOptions {
121
+ /** Target element or selector */
122
+ target: string | HTMLElement;
123
+ /** Form slug */
124
+ slug: string;
125
+ /** Track form views for analytics (completion rate). Default: false */
126
+ trackViews?: boolean;
127
+ /** Custom submit button text */
128
+ submitText?: string;
129
+ /** Success callback */
130
+ onSuccess?: (response: SubmissionResponse) => void;
131
+ /** Error callback */
132
+ onError?: (error: Error) => void;
133
+ /** Validation error callback */
134
+ onValidationError?: (errors: ValidationError[]) => void;
135
+ /** Reset form after submission */
136
+ resetOnSuccess?: boolean;
137
+ /** Redirect after success (overrides form config) */
138
+ redirectUrl?: string;
139
+ }
140
+ /**
141
+ * Form widget for embedding forms
142
+ */
143
+ declare class FormWidget {
144
+ private sdk;
145
+ private container;
146
+ private config;
147
+ private values;
148
+ private errors;
149
+ private isLoading;
150
+ private isSubmitted;
151
+ private options;
152
+ private styleEl;
153
+ constructor(sdkConfig: FormsSDKConfig, options: FormWidgetOptions);
154
+ /**
155
+ * Initialize and render the form
156
+ */
157
+ init(): Promise<void>;
158
+ /**
159
+ * Inject CSS styles
160
+ */
161
+ private injectStyles;
162
+ /**
163
+ * Render the form
164
+ */
165
+ private render;
166
+ /**
167
+ * Handle form submission
168
+ */
169
+ private handleSubmit;
170
+ /**
171
+ * Reset form to initial state
172
+ */
173
+ reset(): void;
174
+ /**
175
+ * Render error message
176
+ */
177
+ private renderError;
178
+ /**
179
+ * Destroy widget
180
+ */
181
+ destroy(): void;
182
+ }
183
+ /**
184
+ * Auto-initialize forms on page load
185
+ */
186
+ declare function autoInit(): void;
187
+
188
+ export { FormWidget, type FormWidgetOptions, autoInit, errorsToRecord, generateFormStyles, renderField, renderForm, renderSuccess };
@@ -0,0 +1,209 @@
1
+ "use strict";var FormsExpert=(()=>{var E=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var U=(t,e)=>{for(var o in e)E(t,o,{get:e[o],enumerable:!0})},O=(t,e,o,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let d of $(e))!L.call(t,d)&&d!==o&&E(t,d,{get:()=>e[d],enumerable:!(r=N(e,d))||r.enumerable});return t};var M=t=>O(E({},"__esModule",{value:!0}),t);var A={};U(A,{FormWidget:()=>y,autoInit:()=>F,errorsToRecord:()=>w,generateFormStyles:()=>C,renderField:()=>T,renderForm:()=>v,renderSuccess:()=>S});var R={theme:"light",primaryColor:"#3b82f6",backgroundColor:"#ffffff",textColor:"#1f2937",borderRadius:"md",fontSize:"md",buttonStyle:"filled",labelPosition:"top"};function P(t){switch(t){case"none":return"0";case"sm":return"0.125rem";case"md":return"0.375rem";case"lg":return"0.5rem";default:return"0.375rem"}}function I(t){switch(t){case"sm":return"0.875rem";case"md":return"1rem";case"lg":return"1.125rem";default:return"1rem"}}function C(t=R){let e={...R,...t},o=P(e.borderRadius),r=I(e.fontSize);return`
2
+ .forms-expert {
3
+ font-family: system-ui, -apple-system, sans-serif;
4
+ font-size: ${r};
5
+ color: ${e.textColor};
6
+ background-color: ${e.backgroundColor};
7
+ padding: 1.5rem;
8
+ border-radius: ${o};
9
+ box-sizing: border-box;
10
+ }
11
+
12
+ .forms-expert * {
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ .forms-expert-group {
17
+ margin-bottom: 1rem;
18
+ ${e.labelPosition==="left"?"display: flex; align-items: flex-start; gap: 1rem;":""}
19
+ }
20
+
21
+ .forms-expert-label {
22
+ display: block;
23
+ font-weight: 500;
24
+ color: ${e.textColor};
25
+ ${e.labelPosition==="left"?"width: 33%; flex-shrink: 0; padding-top: 0.5rem;":"margin-bottom: 0.25rem;"}
26
+ }
27
+
28
+ .forms-expert-required {
29
+ color: #ef4444;
30
+ margin-left: 0.25rem;
31
+ }
32
+
33
+ .forms-expert-input-wrapper {
34
+ ${e.labelPosition==="left"?"flex: 1;":""}
35
+ }
36
+
37
+ .forms-expert-input,
38
+ .forms-expert-textarea,
39
+ .forms-expert-select {
40
+ width: 100%;
41
+ padding: 0.5rem 0.75rem;
42
+ border: 1px solid ${e.theme==="dark"?"#4b5563":"#d1d5db"};
43
+ border-radius: ${o};
44
+ font-size: ${r};
45
+ font-family: inherit;
46
+ background-color: ${e.theme==="dark"?"#374151":"#ffffff"};
47
+ color: ${e.textColor};
48
+ transition: border-color 0.15s, box-shadow 0.15s;
49
+ }
50
+
51
+ .forms-expert-input:focus,
52
+ .forms-expert-textarea:focus,
53
+ .forms-expert-select:focus {
54
+ outline: none;
55
+ border-color: ${e.primaryColor};
56
+ box-shadow: 0 0 0 2px ${e.primaryColor}33;
57
+ }
58
+
59
+ .forms-expert-input.forms-expert-error,
60
+ .forms-expert-textarea.forms-expert-error,
61
+ .forms-expert-select.forms-expert-error {
62
+ border-color: #ef4444;
63
+ }
64
+
65
+ .forms-expert-textarea {
66
+ min-height: 100px;
67
+ resize: vertical;
68
+ }
69
+
70
+ .forms-expert-checkbox-group {
71
+ display: flex;
72
+ align-items: center;
73
+ gap: 0.5rem;
74
+ margin-bottom: 1rem;
75
+ }
76
+
77
+ .forms-expert-checkbox {
78
+ width: 1rem;
79
+ height: 1rem;
80
+ accent-color: ${e.primaryColor};
81
+ cursor: pointer;
82
+ }
83
+
84
+ .forms-expert-file-wrapper {
85
+ position: relative;
86
+ }
87
+
88
+ .forms-expert-file {
89
+ width: 100%;
90
+ padding: 0.5rem 0.75rem;
91
+ border: 1px solid ${e.theme==="dark"?"#4b5563":"#d1d5db"};
92
+ border-radius: ${o};
93
+ font-size: ${r};
94
+ background-color: ${e.theme==="dark"?"#374151":"#ffffff"};
95
+ cursor: pointer;
96
+ }
97
+
98
+ .forms-expert-error-message {
99
+ color: #ef4444;
100
+ font-size: 0.875rem;
101
+ margin-top: 0.25rem;
102
+ }
103
+
104
+ .forms-expert-button {
105
+ width: 100%;
106
+ padding: 0.625rem 1.25rem;
107
+ margin-top: 1rem;
108
+ font-weight: 500;
109
+ font-size: ${r};
110
+ font-family: inherit;
111
+ border-radius: ${o};
112
+ cursor: pointer;
113
+ transition: opacity 0.2s, transform 0.1s;
114
+ ${e.buttonStyle==="filled"?`background-color: ${e.primaryColor}; color: white; border: none;`:`background-color: transparent; color: ${e.primaryColor}; border: 2px solid ${e.primaryColor};`}
115
+ }
116
+
117
+ .forms-expert-button:hover {
118
+ opacity: 0.9;
119
+ }
120
+
121
+ .forms-expert-button:active {
122
+ transform: scale(0.98);
123
+ }
124
+
125
+ .forms-expert-button:disabled {
126
+ opacity: 0.5;
127
+ cursor: not-allowed;
128
+ transform: none;
129
+ }
130
+
131
+ .forms-expert-button-loading {
132
+ display: inline-flex;
133
+ align-items: center;
134
+ justify-content: center;
135
+ gap: 0.5rem;
136
+ }
137
+
138
+ .forms-expert-spinner {
139
+ width: 1rem;
140
+ height: 1rem;
141
+ border: 2px solid transparent;
142
+ border-top-color: currentColor;
143
+ border-radius: 50%;
144
+ animation: forms-expert-spin 0.6s linear infinite;
145
+ }
146
+
147
+ @keyframes forms-expert-spin {
148
+ to { transform: rotate(360deg); }
149
+ }
150
+
151
+ .forms-expert-honeypot {
152
+ position: absolute;
153
+ left: -9999px;
154
+ opacity: 0;
155
+ }
156
+
157
+ .forms-expert-success {
158
+ text-align: center;
159
+ padding: 2rem;
160
+ color: ${e.textColor};
161
+ }
162
+
163
+ .forms-expert-success-icon {
164
+ width: 3rem;
165
+ height: 3rem;
166
+ margin: 0 auto 1rem;
167
+ color: #22c55e;
168
+ }
169
+
170
+ .forms-expert-success-message {
171
+ font-size: 1.125rem;
172
+ font-weight: 500;
173
+ margin-bottom: 0.5rem;
174
+ }
175
+
176
+ .forms-expert-branding {
177
+ text-align: center;
178
+ margin-top: 1rem;
179
+ padding-top: 0.75rem;
180
+ border-top: 1px solid ${e.theme==="dark"?"#374151":"#e5e7eb"};
181
+ }
182
+
183
+ .forms-expert-branding a {
184
+ color: ${e.theme==="dark"?"#9ca3af":"#6b7280"};
185
+ text-decoration: none;
186
+ font-size: 0.75rem;
187
+ }
188
+
189
+ .forms-expert-branding a:hover {
190
+ text-decoration: underline;
191
+ }
192
+
193
+ ${e.customCss||""}
194
+ `.trim()}function f(t){let e=document.createElement("div");return e.textContent=t,e.innerHTML}function T(t,e,o){let r=document.createElement("div");if(t.type==="heading"){r.className="forms-expert-group";let n=document.createElement("h3");if(n.className="forms-expert-heading",n.textContent=t.label||"",r.appendChild(n),t.content){let l=document.createElement("p");l.className="forms-expert-heading-subtitle",l.textContent=t.content,r.appendChild(l)}return r}if(t.type==="divider"){let n=document.createElement("hr");return n.className="forms-expert-divider",n}if(t.type==="paragraph"){if(r.className="forms-expert-group",t.label){let n=document.createElement("p");n.className="forms-expert-paragraph-label",n.textContent=t.label,r.appendChild(n)}if(t.content){let n=document.createElement("p");n.className="forms-expert-paragraph",n.textContent=t.content,r.appendChild(n)}return r}if(t.type==="hidden"){let n=document.createElement("input");return n.type="hidden",n.name=t.name,n.value=String(t.defaultValue??e??""),r.appendChild(n),r.style.display="none",r}if(t.type==="checkbox"||t.type==="toggle"||t.type==="consent"){r.className="forms-expert-checkbox-group";let n=document.createElement("input");n.type="checkbox",n.id=`mira-field-${t.name}`,n.name=t.name,n.className="forms-expert-checkbox",n.checked=!!e,t.required&&(n.required=!0);let l=document.createElement("label");l.htmlFor=n.id;let c=t.type==="consent"?t.consentText||t.label||t.name:t.label||t.name;if(l.innerHTML=`${f(c)}${t.required?'<span class="forms-expert-required">*</span>':""}`,r.appendChild(n),r.appendChild(l),t.type==="consent"&&t.consentUrl){let i=document.createElement("a");i.href=t.consentUrl,i.target="_blank",i.rel="noopener noreferrer",i.textContent="View policy",i.className="forms-expert-consent-link",r.appendChild(i)}if(o){let i=document.createElement("div");i.className="forms-expert-error-message",i.textContent=o,r.appendChild(i)}return r}r.className="forms-expert-group";let d=document.createElement("label");d.className="forms-expert-label",d.htmlFor=`mira-field-${t.name}`,d.innerHTML=`${f(t.label||t.name)}${t.required?'<span class="forms-expert-required">*</span>':""}`,r.appendChild(d);let m=document.createElement("div");m.className="forms-expert-input-wrapper";let s;switch(t.type){case"textarea":case"richText":s=document.createElement("textarea"),s.className="forms-expert-textarea",s.value=String(e||""),t.maxLength&&(s.maxLength=t.maxLength);break;case"select":case"dropdown":{s=document.createElement("select"),s.className="forms-expert-select";let n=document.createElement("option");n.value="",n.textContent=t.placeholder||"Select an option...",s.appendChild(n),(t.options||[]).forEach(c=>{let i=document.createElement("option");i.value=c,i.textContent=c,e===c&&(i.selected=!0),s.appendChild(i)});break}case"radio":{let n=document.createElement("div");if(n.className="forms-expert-radio-group",(t.options||[]).forEach(c=>{let i=document.createElement("label");i.className="forms-expert-radio-item";let a=document.createElement("input");a.type="radio",a.name=t.name,a.value=c,a.checked=e===c,i.appendChild(a),i.appendChild(document.createTextNode(` ${c}`)),n.appendChild(i)}),m.appendChild(n),o){let c=document.createElement("div");c.className="forms-expert-error-message",c.textContent=o,m.appendChild(c)}return r.appendChild(m),r}case"multiselect":{let n=document.createElement("div");n.className="forms-expert-multiselect-group";let l=e||[];if((t.options||[]).forEach(i=>{let a=document.createElement("label");a.className="forms-expert-checkbox-item";let p=document.createElement("input");p.type="checkbox",p.name=t.name,p.value=i,p.checked=l.includes(i),a.appendChild(p),a.appendChild(document.createTextNode(` ${i}`)),n.appendChild(a)}),m.appendChild(n),o){let i=document.createElement("div");i.className="forms-expert-error-message",i.textContent=o,m.appendChild(i)}return r.appendChild(m),r}case"rating":{let n=document.createElement("div");n.className="forms-expert-rating";let l=t.ratingMax||5,c=e||0;for(let i=1;i<=l;i++){let a=document.createElement("button");a.type="button",a.className=`forms-expert-rating-star ${i<=c?"active":""}`,a.textContent="\u2605",a.dataset.value=String(i),n.appendChild(a)}if(m.appendChild(n),o){let i=document.createElement("div");i.className="forms-expert-error-message",i.textContent=o,m.appendChild(i)}return r.appendChild(m),r}case"scale":case"opinionScale":{let n=document.createElement("div");n.className="forms-expert-scale";let l=t.min??(t.type==="opinionScale"?0:1),c=t.max??(t.type==="opinionScale"?10:5),i=e;for(let a=l;a<=c;a++){let p=document.createElement("button");p.type="button",p.className=`forms-expert-scale-btn ${i===a?"active":""}`,p.textContent=String(a),p.dataset.value=String(a),n.appendChild(p)}if(m.appendChild(n),t.lowLabel||t.highLabel){let a=document.createElement("div");a.className="forms-expert-scale-labels",a.innerHTML=`<span>${f(t.lowLabel||"")}</span><span>${f(t.highLabel||"")}</span>`,m.appendChild(a)}if(o){let a=document.createElement("div");a.className="forms-expert-error-message",a.textContent=o,m.appendChild(a)}return r.appendChild(m),r}case"slider":{s=document.createElement("input"),s.type="range",s.className="forms-expert-slider",s.min=String(t.min??0),s.max=String(t.max??100),s.step=String(t.step??1),s.value=String(e??t.min??0);break}case"file":s=document.createElement("input"),s.type="file",s.className="forms-expert-file",t.allowedMimeTypes?.length&&(s.accept=t.allowedMimeTypes.join(",")),t.multiple&&(s.multiple=!0);break;case"currency":{s=document.createElement("input"),s.type="number",s.className="forms-expert-input",s.value=String(e??""),t.min!==void 0&&(s.min=String(t.min)),t.max!==void 0&&(s.max=String(t.max)),s.step=String(t.step||.01);break}case"phone":s=document.createElement("input"),s.type="tel",s.className="forms-expert-input",s.value=String(e||"");break;case"url":s=document.createElement("input"),s.type="url",s.className="forms-expert-input",s.value=String(e||"");break;case"password":s=document.createElement("input"),s.type="password",s.className="forms-expert-input",s.value=String(e||"");break;case"time":s=document.createElement("input"),s.type="time",s.className="forms-expert-input",s.value=String(e||"");break;case"datetime":s=document.createElement("input"),s.type="datetime-local",s.className="forms-expert-input",s.value=String(e||"");break;case"colorPicker":s=document.createElement("input"),s.type="color",s.className="forms-expert-color",s.value=String(e||"#000000");break;case"dateRange":{let n=document.createElement("div");n.className="forms-expert-date-range";let l=e||{},c=document.createElement("input");c.type="date",c.className="forms-expert-input",c.name=`${t.name}.start`,c.value=l.start||"";let i=document.createElement("input");if(i.type="date",i.className="forms-expert-input",i.name=`${t.name}.end`,i.value=l.end||"",n.appendChild(c),n.appendChild(i),m.appendChild(n),o){let a=document.createElement("div");a.className="forms-expert-error-message",a.textContent=o,m.appendChild(a)}return r.appendChild(m),r}case"address":{let n=document.createElement("div");n.className="forms-expert-address";let l=t.addressFields||["street","city","state","zip","country"],c=e||{},i={street:"Street",street2:"Street Line 2",city:"City",state:"State",zip:"ZIP",country:"Country"};if(l.forEach(a=>{let p=document.createElement("input");p.type="text",p.className="forms-expert-input",p.name=`${t.name}.${a}`,p.placeholder=i[a]||a,p.value=c[a]||"",n.appendChild(p)}),m.appendChild(n),o){let a=document.createElement("div");a.className="forms-expert-error-message",a.textContent=o,m.appendChild(a)}return r.appendChild(m),r}case"name":{let n=document.createElement("div");n.className="forms-expert-name";let l=t.nameFields||["first","last"],c=e||{},i={prefix:"Prefix",first:"First Name",middle:"Middle",last:"Last Name",suffix:"Suffix"};if(l.forEach(a=>{let p=document.createElement("input");p.type="text",p.className="forms-expert-input",p.name=`${t.name}.${a}`,p.placeholder=i[a]||a,p.value=c[a]||"",n.appendChild(p)}),m.appendChild(n),o){let a=document.createElement("div");a.className="forms-expert-error-message",a.textContent=o,m.appendChild(a)}return r.appendChild(m),r}case"imageChoice":{let n=document.createElement("div");n.className="forms-expert-image-choice";let l=t.options||[],c=e;if(l.forEach(i=>{let a=document.createElement("button");if(a.type="button",a.className=`forms-expert-image-choice-item ${c===i.value?"active":""}`,a.dataset.value=i.value,i.imageUrl){let g=document.createElement("img");g.src=i.imageUrl,g.alt=i.label,a.appendChild(g)}let p=document.createElement("span");p.textContent=i.label,a.appendChild(p),n.appendChild(a)}),m.appendChild(n),o){let i=document.createElement("div");i.className="forms-expert-error-message",i.textContent=o,m.appendChild(i)}return r.appendChild(m),r}case"ranking":{let n=document.createElement("div");n.className="forms-expert-ranking";let l=t.options||[];if((e||[...l]).forEach((i,a)=>{let p=document.createElement("div");p.className="forms-expert-ranking-item",p.textContent=`${a+1}. ${i}`,p.dataset.value=i,n.appendChild(p)}),m.appendChild(n),o){let i=document.createElement("div");i.className="forms-expert-error-message",i.textContent=o,m.appendChild(i)}return r.appendChild(m),r}case"location":{let n=document.createElement("div");n.className="forms-expert-location";let l=e||{},c=document.createElement("input");c.type="text",c.className="forms-expert-input",c.name=`${t.name}.address`,c.placeholder="Address",c.value=l.address||"",n.appendChild(c);let i=document.createElement("div");i.className="forms-expert-location-coords";let a=document.createElement("input");a.type="number",a.className="forms-expert-input",a.name=`${t.name}.lat`,a.placeholder="Latitude",a.step="any",a.value=l.lat!==void 0?String(l.lat):"";let p=document.createElement("input");if(p.type="number",p.className="forms-expert-input",p.name=`${t.name}.lng`,p.placeholder="Longitude",p.step="any",p.value=l.lng!==void 0?String(l.lng):"",i.appendChild(a),i.appendChild(p),n.appendChild(i),m.appendChild(n),o){let g=document.createElement("div");g.className="forms-expert-error-message",g.textContent=o,m.appendChild(g)}return r.appendChild(m),r}default:s=document.createElement("input"),s.type=t.type==="email"?"email":t.type==="number"?"number":t.type==="date"?"date":"text",s.className="forms-expert-input",s.value=String(e||""),t.type==="number"&&(t.min!==void 0&&(s.min=String(t.min)),t.max!==void 0&&(s.max=String(t.max)),t.step!==void 0&&(s.step=String(t.step)));break}if(s.id=`mira-field-${t.name}`,s.name=t.name,t.placeholder&&"placeholder"in s&&(s.placeholder=t.placeholder),t.required&&(s.required=!0),o&&s.classList.add("forms-expert-error"),m.appendChild(s),o){let n=document.createElement("div");n.className="forms-expert-error-message",n.textContent=o,m.appendChild(n)}return r.appendChild(m),r}function v(t,e={},o={},r={}){let d=document.createElement("form");if(d.className="forms-expert",t.fields.forEach(n=>{let l=T(n,e[n.name],o[n.name]);d.appendChild(l)}),r.honeypot){let n=document.createElement("input");n.type="text",n.name="_hp",n.className="forms-expert-honeypot",n.tabIndex=-1,n.autocomplete="off",d.appendChild(n)}let m=document.createElement("input");m.type="hidden",m.name="pageUrl",m.value=typeof window<"u"?window.location.href:"",d.appendChild(m);let s=document.createElement("button");if(s.type="submit",s.className="forms-expert-button",s.disabled=r.isLoading||!1,r.isLoading?s.innerHTML=`
195
+ <span class="forms-expert-button-loading">
196
+ <span class="forms-expert-spinner"></span>
197
+ Submitting...
198
+ </span>
199
+ `:s.textContent=r.submitText||"Submit",d.appendChild(s),r.showBranding!==!1){let n=r.brandingText||"Powered by Forms Expert",l=r.brandingUrl||"https://mira.io",c=document.createElement("div");c.className="forms-expert-branding",c.innerHTML=`<a href="${l}" target="_blank" rel="noopener">${n}</a>`,d.appendChild(c)}return d}function S(t){let e=document.createElement("div");return e.className="forms-expert-success",e.innerHTML=`
200
+ <svg class="forms-expert-success-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
201
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
202
+ </svg>
203
+ <div class="forms-expert-success-message">${f(t)}</div>
204
+ `,e}function w(t){return t.reduce((e,o)=>({...e,[o.field]:o.message}),{})}var u=class extends Error{constructor(o,r,d,m){super(o);this.code=r;this.statusCode=d;this.retryAfter=m;this.name="FormsError"}},h=class extends Error{constructor(o){super("Validation failed");this.errors=o;this.name="FormValidationError"}};var x=class{constructor(e){this.apiKey=e.apiKey,this.resourceId=e.resourceId,this.baseUrl=(e.baseUrl||"https://api.formsapp.io/api/v1").replace(/\/$/,"")}buildUrl(e){let o=e.includes("?")?"&":"?";return`${this.baseUrl}${e}${o}token=${encodeURIComponent(this.apiKey)}`}async request(e,o,r){let d=this.buildUrl(o),m=await fetch(d,{method:e,headers:{"Content-Type":"application/json"},body:r?JSON.stringify(r):void 0}),s=await m.json();if(!m.ok)throw new u(s.message||"Request failed",s.code||"UNKNOWN_ERROR",m.status,s.retryAfter);return s}async isActive(e){return this.request("GET",`/f/${this.resourceId}/${e}/is-active`)}async validate(e,o){return this.request("POST",`/f/${this.resourceId}/${e}/validate`,{data:o})}async submit(e,o,r){let d=this.buildUrl(`/f/${this.resourceId}/${e}`);return Object.values(o).some(s=>s instanceof File||s instanceof FileList&&s.length>0)||r?.onProgress?this.submitWithFormData(d,o,r):this.request("POST",`/f/${this.resourceId}/${e}`,{data:o,pageUrl:r?.pageUrl||(typeof window<"u"?window.location.href:void 0),captchaToken:r?.captchaToken})}submitWithFormData(e,o,r){return new Promise((d,m)=>{let s=new FormData;for(let[c,i]of Object.entries(o))i instanceof File?s.append(c,i):i instanceof FileList?Array.from(i).forEach(a=>s.append(c,a)):i!=null&&s.append(`data[${c}]`,String(i));let n=r?.pageUrl||(typeof window<"u"?window.location.href:"");n&&s.append("pageUrl",n),r?.captchaToken&&s.append("captchaToken",r.captchaToken);let l=new XMLHttpRequest;r?.onProgress&&l.upload.addEventListener("progress",c=>{c.lengthComputable&&r.onProgress({loaded:c.loaded,total:c.total,percentage:Math.round(c.loaded/c.total*100)})}),l.addEventListener("load",()=>{try{let c=JSON.parse(l.responseText);l.status>=200&&l.status<300?d(c):m(new u(c.message||"Submission failed",c.code||"UNKNOWN_ERROR",l.status,c.retryAfter))}catch{m(new u("Invalid response","PARSE_ERROR",l.status))}}),l.addEventListener("error",()=>{m(new u("Network error","NETWORK_ERROR",0))}),l.addEventListener("abort",()=>{m(new u("Request aborted","ABORTED",0))}),l.open("POST",e),l.send(s)})}async trackView(e){let o=this.buildUrl(`/f/${this.resourceId}/${e}/view`);await fetch(o,{method:"POST",headers:{"Content-Type":"application/json"}}).catch(()=>{})}getResourceId(){return this.resourceId}getBaseUrl(){return this.baseUrl}};var k=class{constructor(e,o,r={}){this.config=null;this.apiClient=e,this.slug=o,this.options=r}async initialize(){return this.config=await this.apiClient.isActive(this.slug),this.options.trackViews&&this.apiClient.trackView(this.slug),this.config}getConfig(){return this.config}isActive(){return this.config?.active??!1}requiresCaptcha(){return this.config?.settings?.captcha?.enabled??!1}getCaptchaProvider(){return this.config?.settings?.captcha?.provider}getSchema(){return this.config?.schema}async validate(e){return this.apiClient.validate(this.slug,e)}async submit(e,o){this.options.onSubmitStart?.();try{if(this.config?.mode==="schema"){let d=await this.validate(e);if(!d.valid)throw this.options.onValidationError?.(d.errors),new h(d.errors)}let r=await this.apiClient.submit(this.slug,e,o);return this.options.onSubmitSuccess?.(r),r}catch(r){throw r instanceof u&&this.options.onSubmitError?.(r),r}}getSuccessMessage(){return this.config?.settings?.successMessage||"Form submitted successfully!"}getRedirectUrl(){return this.config?.settings?.redirectUrl}},b=class{constructor(e){this.apiClient=new x(e)}async isActive(e){return this.apiClient.isActive(e)}async validate(e,o){return this.apiClient.validate(e,o)}async submit(e,o,r){return this.apiClient.submit(e,o,r)}form(e,o){return new k(this.apiClient,e,o)}async trackView(e){return this.apiClient.trackView(e)}async submitWithRetry(e,o,r){let d=r?.maxRetries??3,m=null;for(let s=0;s<d;s++)try{return await this.submit(e,o,r)}catch(n){if(m=n,n instanceof u){if(["VALIDATION_ERROR","CAPTCHA_REQUIRED","ORIGIN_NOT_ALLOWED"].includes(n.code))throw n;if(n.code.includes("RATE_LIMIT")){let l=n.retryAfter||Math.pow(2,s)*1e3;await new Promise(c=>setTimeout(c,l));continue}}await new Promise(l=>setTimeout(l,Math.pow(2,s)*1e3))}throw m}};var y=class{constructor(e,o){this.config=null;this.values={};this.errors={};this.isLoading=!1;this.isSubmitted=!1;this.styleEl=null;this.sdk=new b(e),this.options=o;let r=o.target;if(typeof r=="string"){let d=document.querySelector(r);if(!d)throw new Error(`Element not found: ${r}`);this.container=d}else this.container=r}async init(){try{if(this.config=await this.sdk.isActive(this.options.slug),!this.config.active){this.renderError("This form is not available");return}this.options.trackViews&&this.sdk.trackView(this.options.slug),this.injectStyles(),this.render()}catch(e){this.renderError("Failed to load form"),this.options.onError?.(e)}}injectStyles(){this.styleEl||(this.styleEl=document.createElement("style"),this.styleEl.id=`forms-expert-styles-${this.options.slug}`,this.styleEl.textContent=C(this.config?.schema?.styling),document.head.appendChild(this.styleEl))}render(){if(!this.config?.schema)return;if(this.isSubmitted){this.container.innerHTML="";let o=this.config.settings?.successMessage||"Form submitted successfully!";this.container.appendChild(S(o));return}let e=v(this.config.schema,this.values,this.errors,{honeypot:this.config.settings?.honeypot,showBranding:this.config.branding?.enabled!==!1,brandingText:this.config.branding?.text,brandingUrl:this.config.branding?.url,submitText:this.options.submitText,isLoading:this.isLoading});e.addEventListener("input",o=>{let r=o.target;r.name&&r.name!=="_hp"&&r.name!=="pageUrl"&&(r.type==="checkbox"?this.values[r.name]=r.checked:r.type==="file"?this.values[r.name]=r.multiple?r.files:r.files?.[0]:this.values[r.name]=r.value,this.errors[r.name]&&(delete this.errors[r.name],this.render()))}),e.addEventListener("submit",o=>{o.preventDefault(),this.handleSubmit()}),this.container.innerHTML="",this.container.appendChild(e)}async handleSubmit(){if(!(this.isLoading||!this.config)){this.isLoading=!0,this.errors={},this.render();try{let e=await this.sdk.submit(this.options.slug,this.values);this.isLoading=!1,this.isSubmitted=!0,this.render(),this.options.onSuccess?.(e);let o=this.options.redirectUrl||this.config.settings?.redirectUrl;o&&setTimeout(()=>{window.location.href=o},1500),this.options.resetOnSuccess&&setTimeout(()=>{this.reset()},3e3)}catch(e){this.isLoading=!1,e instanceof h?(this.errors=w(e.errors),this.options.onValidationError?.(e.errors)):this.options.onError?.(e),this.render()}}}reset(){this.values={},this.errors={},this.isLoading=!1,this.isSubmitted=!1,this.render()}renderError(e){this.container.innerHTML=`
205
+ <div class="forms-expert" style="text-align: center; padding: 2rem; color: #ef4444;">
206
+ <p>${e}</p>
207
+ </div>
208
+ `}destroy(){this.container.innerHTML="",this.styleEl?.remove(),this.styleEl=null}};function F(){document.querySelectorAll("[data-forms-expert]").forEach(e=>{let o=e.getAttribute("data-api-key"),r=e.getAttribute("data-resource-id"),d=e.getAttribute("data-forms-expert"),m=e.getAttribute("data-base-url")||void 0;if(!o||!r||!d){console.error("Forms Expert: Missing required attributes",{apiKey:!!o,resourceId:!!r,slug:!!d});return}new y({apiKey:o,resourceId:r,baseUrl:m},{target:e,slug:d,trackViews:e.getAttribute("data-track-views")==="true",submitText:e.getAttribute("data-submit-text")||void 0,resetOnSuccess:e.getAttribute("data-reset")==="true"}).init()})}typeof window<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",F):F());return M(A);})();
209
+ //# sourceMappingURL=index.global.js.map