@nuasite/components 0.15.1 → 0.16.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.
- package/package.json +1 -1
- package/src/form/index.astro +23 -0
package/package.json
CHANGED
package/src/form/index.astro
CHANGED
|
@@ -70,12 +70,15 @@ const tokenId = `${tokenFieldName}_${formId}`
|
|
|
70
70
|
))}
|
|
71
71
|
</div>
|
|
72
72
|
|
|
73
|
+
<label for={cssHoneypotField} class="sr-only">Leave this field empty</label>
|
|
73
74
|
<input
|
|
74
75
|
type="text"
|
|
76
|
+
id={cssHoneypotField}
|
|
75
77
|
name={cssHoneypotField}
|
|
76
78
|
style="position: absolute; left: -9999px; opacity: 0;"
|
|
77
79
|
tabindex="-1"
|
|
78
80
|
autocomplete="nope"
|
|
81
|
+
aria-hidden="true"
|
|
79
82
|
/>
|
|
80
83
|
|
|
81
84
|
<slot />
|
|
@@ -216,16 +219,32 @@ const tokenId = `${tokenFieldName}_${formId}`
|
|
|
216
219
|
|
|
217
220
|
refreshSubmissionGuards()
|
|
218
221
|
|
|
222
|
+
const trackForm = (action: string, detail?: Record<string, unknown>) => {
|
|
223
|
+
if (typeof window !== 'undefined' && (window as any).analytics?.form) {
|
|
224
|
+
(window as any).analytics.form(formId, action, detail)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
219
228
|
form.addEventListener('submit', async (e) => {
|
|
220
229
|
e.preventDefault()
|
|
221
230
|
|
|
231
|
+
const formDataForTracking = Object.fromEntries(
|
|
232
|
+
Array.from(new FormData(form).entries())
|
|
233
|
+
.filter(([k]) => !this.honeypotFieldNames.includes(k) && !/^token_/.test(k) && !form.querySelector(`[name="${k}"][aria-hidden="true"]`))
|
|
234
|
+
.map(([k, v]) => [k, typeof v === 'string' ? v.slice(0, 100) : '[File]']),
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
trackForm('attempt', { formData: formDataForTracking })
|
|
238
|
+
|
|
222
239
|
if (!this.passesHumanityChecks(form)) {
|
|
240
|
+
trackForm('reject', { reason: 'humanity_check_failed', formData: formDataForTracking })
|
|
223
241
|
showError(tryAgainMessage)
|
|
224
242
|
return
|
|
225
243
|
}
|
|
226
244
|
|
|
227
245
|
const elapsed = performance.now() - activationTime
|
|
228
246
|
if (minSubmitDelay > 0 && elapsed < minSubmitDelay) {
|
|
247
|
+
trackForm('reject', { reason: 'submitted_too_fast', formData: formDataForTracking })
|
|
229
248
|
showError(fastSubmitMessage || tryAgainMessage)
|
|
230
249
|
return
|
|
231
250
|
}
|
|
@@ -233,6 +252,7 @@ const tokenId = `${tokenFieldName}_${formId}`
|
|
|
233
252
|
activationTime = performance.now()
|
|
234
253
|
|
|
235
254
|
if (tokenInput && !tokenInput.value) {
|
|
255
|
+
trackForm('reject', { reason: 'missing_token', formData: formDataForTracking })
|
|
236
256
|
showError(tryAgainMessage)
|
|
237
257
|
return
|
|
238
258
|
}
|
|
@@ -251,15 +271,18 @@ const tokenId = `${tokenFieldName}_${formId}`
|
|
|
251
271
|
|
|
252
272
|
if (response.ok && 'success' in result && result.success) {
|
|
253
273
|
const message = hasCustomSuccess ? successMessage : (result.message || successMessage)
|
|
274
|
+
trackForm('success', { formData: formDataForTracking })
|
|
254
275
|
showSuccess(message)
|
|
255
276
|
form.reset()
|
|
256
277
|
refreshSubmissionGuards()
|
|
257
278
|
} else {
|
|
258
279
|
const message = hasCustomError ? errorMessage : (result.error || result.message || errorMessage)
|
|
280
|
+
trackForm('error', { reason: result.error || `http_${response.status}`, formData: formDataForTracking })
|
|
259
281
|
showError(message)
|
|
260
282
|
}
|
|
261
283
|
} catch (err) {
|
|
262
284
|
console.error('Form submission error:', err);
|
|
285
|
+
trackForm('error', { reason: err instanceof Error ? err.message : 'network_error', formData: formDataForTracking })
|
|
263
286
|
showError(networkErrorMessage)
|
|
264
287
|
}
|
|
265
288
|
})
|