@letar/forms 1.1.0 → 1.2.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +308 -0
  2. package/README.md +9 -9
  3. package/README.ru.md +115 -30
  4. package/analytics.js +3 -0
  5. package/analytics.js.map +1 -0
  6. package/chunk-2PSXYC3I.js +1782 -0
  7. package/chunk-2PSXYC3I.js.map +1 -0
  8. package/chunk-5D6S6EGF.js +206 -0
  9. package/chunk-5D6S6EGF.js.map +1 -0
  10. package/{chunk-6QOPSQ3Z.js → chunk-6E7VJAJT.js} +3 -3
  11. package/{chunk-6QOPSQ3Z.js.map → chunk-6E7VJAJT.js.map} +1 -1
  12. package/chunk-CGXKRCSM.js +117 -0
  13. package/chunk-CGXKRCSM.js.map +1 -0
  14. package/{chunk-M2PNAAIR.js → chunk-DQUVUMCX.js} +30 -19
  15. package/chunk-DQUVUMCX.js.map +1 -0
  16. package/chunk-K3J4L26K.js +345 -0
  17. package/chunk-K3J4L26K.js.map +1 -0
  18. package/{chunk-PJETA6YN.js → chunk-MAYUFA5K.js} +5 -4
  19. package/chunk-MAYUFA5K.js.map +1 -0
  20. package/{chunk-4V6WBJ76.js → chunk-MVGXZNHP.js} +2 -2
  21. package/{chunk-4V6WBJ76.js.map → chunk-MVGXZNHP.js.map} +1 -1
  22. package/{chunk-XKKJKYWZ.js → chunk-MZDTJSF7.js} +3 -3
  23. package/{chunk-XKKJKYWZ.js.map → chunk-MZDTJSF7.js.map} +1 -1
  24. package/{chunk-KUNT5MSU.js → chunk-Q5EOF36Y.js} +3 -3
  25. package/chunk-Q5EOF36Y.js.map +1 -0
  26. package/{chunk-7FEQFDJ7.js → chunk-R2RTCKXY.js} +2 -2
  27. package/{chunk-7FEQFDJ7.js.map → chunk-R2RTCKXY.js.map} +1 -1
  28. package/{chunk-HWVOFWAT.js → chunk-XFWLD5EO.js} +225 -26
  29. package/chunk-XFWLD5EO.js.map +1 -0
  30. package/fields/boolean.js +3 -3
  31. package/fields/datetime.js +3 -3
  32. package/fields/number.js +3 -3
  33. package/fields/selection.js +3 -3
  34. package/fields/specialized.js +3 -3
  35. package/fields/text.js +3 -3
  36. package/hcaptcha-U4XIT3HS.js +64 -0
  37. package/hcaptcha-U4XIT3HS.js.map +1 -0
  38. package/i18n.js +1 -1
  39. package/index.js +3268 -51
  40. package/index.js.map +1 -1
  41. package/offline.js +1 -1
  42. package/package.json +33 -4
  43. package/recaptcha-PKAUAY2S.js +56 -0
  44. package/recaptcha-PKAUAY2S.js.map +1 -0
  45. package/server-errors.js +3 -0
  46. package/server-errors.js.map +1 -0
  47. package/turnstile-7FXTBSLW.js +36 -0
  48. package/turnstile-7FXTBSLW.js.map +1 -0
  49. package/validators/ru.js +73 -0
  50. package/validators/ru.js.map +1 -0
  51. package/chunk-GOELIS6T.js +0 -849
  52. package/chunk-GOELIS6T.js.map +0 -1
  53. package/chunk-HWVOFWAT.js.map +0 -1
  54. package/chunk-KUNT5MSU.js.map +0 -1
  55. package/chunk-M2PNAAIR.js.map +0 -1
  56. package/chunk-PJETA6YN.js.map +0 -1
@@ -0,0 +1,345 @@
1
+ import { Box, Text, HStack, VStack, Code } from '@chakra-ui/react';
2
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
+ import { useState, useRef, useCallback, useEffect } from 'react';
4
+
5
+ // src/lib/analytics/analytics-panel.tsx
6
+ function AnalyticsPanel({ analytics, position = "bottom-right" }) {
7
+ const positionStyles = {
8
+ "bottom-right": { bottom: 4, right: 4 },
9
+ "bottom-left": { bottom: 4, left: 4 },
10
+ "top-right": { top: 4, right: 4 },
11
+ "top-left": { top: 4, left: 4 }
12
+ };
13
+ const topFields = Array.from(analytics.fieldAnalytics.entries()).sort((a, b) => b[1].totalTimeMs - a[1].totalTimeMs).slice(0, 5);
14
+ return /* @__PURE__ */ jsxs(
15
+ Box,
16
+ {
17
+ position: "fixed",
18
+ ...positionStyles[position],
19
+ zIndex: 9999,
20
+ bg: "gray.900",
21
+ color: "white",
22
+ p: 3,
23
+ borderRadius: "md",
24
+ fontSize: "xs",
25
+ maxW: "300px",
26
+ opacity: 0.9,
27
+ boxShadow: "lg",
28
+ children: [
29
+ /* @__PURE__ */ jsx(Text, { fontWeight: "bold", mb: 2, children: "Form Analytics" }),
30
+ /* @__PURE__ */ jsxs(HStack, { gap: 4, mb: 2, children: [
31
+ /* @__PURE__ */ jsxs(VStack, { gap: 0, align: "start", children: [
32
+ /* @__PURE__ */ jsx(Text, { color: "gray.400", children: "Completion" }),
33
+ /* @__PURE__ */ jsxs(Text, { fontWeight: "bold", color: analytics.completionRate > 80 ? "green.400" : "yellow.400", children: [
34
+ analytics.completionRate,
35
+ "%"
36
+ ] })
37
+ ] }),
38
+ /* @__PURE__ */ jsxs(VStack, { gap: 0, align: "start", children: [
39
+ /* @__PURE__ */ jsx(Text, { color: "gray.400", children: "Errors" }),
40
+ /* @__PURE__ */ jsx(Text, { fontWeight: "bold", color: analytics.totalErrors > 0 ? "red.400" : "green.400", children: analytics.totalErrors })
41
+ ] }),
42
+ /* @__PURE__ */ jsxs(VStack, { gap: 0, align: "start", children: [
43
+ /* @__PURE__ */ jsx(Text, { color: "gray.400", children: "Time" }),
44
+ /* @__PURE__ */ jsxs(Text, { fontWeight: "bold", children: [
45
+ Math.round(analytics.totalTimeMs / 1e3),
46
+ "s"
47
+ ] })
48
+ ] })
49
+ ] }),
50
+ topFields.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
51
+ /* @__PURE__ */ jsx(Text, { color: "gray.400", mb: 1, children: "Top fields by time:" }),
52
+ topFields.map(([field, fa]) => /* @__PURE__ */ jsxs(HStack, { justify: "space-between", children: [
53
+ /* @__PURE__ */ jsx(Code, { fontSize: "xs", bg: "transparent", color: "gray.300", children: field }),
54
+ /* @__PURE__ */ jsxs(Text, { children: [
55
+ Math.round(fa.totalTimeMs / 1e3),
56
+ "s ",
57
+ fa.errorCount > 0 && `(${fa.errorCount} err)`
58
+ ] })
59
+ ] }, field))
60
+ ] }),
61
+ analytics.lastFocusedField && /* @__PURE__ */ jsxs(Text, { color: "gray.500", mt: 1, children: [
62
+ "Last: ",
63
+ analytics.lastFocusedField
64
+ ] })
65
+ ]
66
+ }
67
+ );
68
+ }
69
+ function useFormAnalytics(config) {
70
+ const { enabled = true, formId, adapters = [], trackCorrections = true } = config ?? {};
71
+ const [fieldAnalytics, setFieldAnalytics] = useState(/* @__PURE__ */ new Map());
72
+ const [lastFocusedField, setLastFocusedField] = useState(null);
73
+ const startTimeRef = useRef(Date.now());
74
+ const focusTimeRef = useRef(/* @__PURE__ */ new Map());
75
+ const blurredFieldsRef = useRef(/* @__PURE__ */ new Set());
76
+ const emit = useCallback((event) => {
77
+ if (!enabled) return;
78
+ for (const adapter of adapters) {
79
+ try {
80
+ adapter.track(event, formId);
81
+ } catch {
82
+ }
83
+ }
84
+ switch (event.type) {
85
+ case "field_focus":
86
+ config?.onFieldFocus?.(event.field, event.timestamp);
87
+ break;
88
+ case "field_blur":
89
+ config?.onFieldBlur?.(event.field, event.timestamp, event.timeSpentMs);
90
+ break;
91
+ case "field_error":
92
+ config?.onFieldError?.(event.field, event.error);
93
+ break;
94
+ case "step_change":
95
+ config?.onStepChange?.(event.from, event.to);
96
+ break;
97
+ case "form_abandon":
98
+ config?.onAbandon?.(event.lastField, event.filledFields, event.totalFields);
99
+ break;
100
+ case "form_complete":
101
+ config?.onComplete?.(event.totalTimeMs, event.fieldTimes);
102
+ break;
103
+ }
104
+ }, [enabled, adapters, formId, config]);
105
+ useEffect(() => {
106
+ if (!enabled) return;
107
+ for (const adapter of adapters) {
108
+ try {
109
+ adapter.init?.();
110
+ } catch {
111
+ }
112
+ }
113
+ return () => {
114
+ for (const adapter of adapters) {
115
+ try {
116
+ adapter.destroy?.();
117
+ } catch {
118
+ }
119
+ }
120
+ };
121
+ }, [enabled, adapters]);
122
+ const trackFocus = useCallback((field) => {
123
+ if (!enabled) return;
124
+ const now = Date.now();
125
+ focusTimeRef.current.set(field, now);
126
+ setLastFocusedField(field);
127
+ setFieldAnalytics((prev) => {
128
+ const next = new Map(prev);
129
+ const existing = next.get(field) ?? createEmptyAnalytics();
130
+ const isCorrection = trackCorrections && blurredFieldsRef.current.has(field);
131
+ next.set(field, {
132
+ ...existing,
133
+ focusCount: existing.focusCount + 1,
134
+ firstFocusAt: existing.firstFocusAt ?? now,
135
+ correctionCount: existing.correctionCount + (isCorrection ? 1 : 0)
136
+ });
137
+ return next;
138
+ });
139
+ emit({ type: "field_focus", field, timestamp: now });
140
+ if (trackCorrections && blurredFieldsRef.current.has(field)) {
141
+ const analytics = fieldAnalytics.get(field);
142
+ emit({ type: "field_correction", field, timestamp: now, correctionCount: (analytics?.correctionCount ?? 0) + 1 });
143
+ }
144
+ }, [enabled, trackCorrections, fieldAnalytics, emit]);
145
+ const trackBlur = useCallback((field) => {
146
+ if (!enabled) return;
147
+ const now = Date.now();
148
+ const focusTime = focusTimeRef.current.get(field);
149
+ const timeSpentMs = focusTime ? now - focusTime : 0;
150
+ blurredFieldsRef.current.add(field);
151
+ setFieldAnalytics((prev) => {
152
+ const next = new Map(prev);
153
+ const existing = next.get(field) ?? createEmptyAnalytics();
154
+ next.set(field, { ...existing, totalTimeMs: existing.totalTimeMs + timeSpentMs, lastBlurAt: now });
155
+ return next;
156
+ });
157
+ emit({ type: "field_blur", field, timestamp: now, timeSpentMs });
158
+ }, [enabled, emit]);
159
+ useCallback((field, error) => {
160
+ if (!enabled) return;
161
+ setFieldAnalytics((prev) => {
162
+ const next = new Map(prev);
163
+ const existing = next.get(field) ?? createEmptyAnalytics();
164
+ next.set(field, { ...existing, errorCount: existing.errorCount + 1 });
165
+ return next;
166
+ });
167
+ emit({ type: "field_error", field, error, timestamp: Date.now() });
168
+ }, [enabled, emit]);
169
+ useEffect(() => {
170
+ if (!enabled || typeof document === "undefined") return;
171
+ const handleFocus = (e) => {
172
+ const target = e.target;
173
+ const name = target.getAttribute("name");
174
+ if (name) trackFocus(name);
175
+ };
176
+ const handleBlur = (e) => {
177
+ const target = e.target;
178
+ const name = target.getAttribute("name");
179
+ if (name) trackBlur(name);
180
+ };
181
+ document.addEventListener("focusin", handleFocus, true);
182
+ document.addEventListener("focusout", handleBlur, true);
183
+ return () => {
184
+ document.removeEventListener("focusin", handleFocus, true);
185
+ document.removeEventListener("focusout", handleBlur, true);
186
+ };
187
+ }, [enabled, trackFocus, trackBlur]);
188
+ useEffect(() => {
189
+ if (!enabled || typeof window === "undefined") return;
190
+ const handleBeforeUnload = () => {
191
+ if (lastFocusedField && fieldAnalytics.size > 0) {
192
+ emit({
193
+ type: "form_abandon",
194
+ lastField: lastFocusedField,
195
+ filledFields: fieldAnalytics.size,
196
+ totalFields: fieldAnalytics.size,
197
+ // приблизительно
198
+ timestamp: Date.now(),
199
+ totalTimeMs: Date.now() - startTimeRef.current
200
+ });
201
+ }
202
+ };
203
+ window.addEventListener("beforeunload", handleBeforeUnload);
204
+ return () => window.removeEventListener("beforeunload", handleBeforeUnload);
205
+ }, [enabled, lastFocusedField, fieldAnalytics, emit]);
206
+ const totalTimeMs = Date.now() - startTimeRef.current;
207
+ const totalErrors = Array.from(fieldAnalytics.values()).reduce((sum, fa) => sum + fa.errorCount, 0);
208
+ const fieldsWithBlur = Array.from(fieldAnalytics.values()).filter((fa) => fa.lastBlurAt !== null).length;
209
+ const totalFieldsTracked = fieldAnalytics.size || 1;
210
+ const completionRate = Math.round(fieldsWithBlur / totalFieldsTracked * 100);
211
+ const trackAbandon = useCallback(() => {
212
+ emit({
213
+ type: "form_abandon",
214
+ lastField: lastFocusedField ?? "",
215
+ filledFields: fieldsWithBlur,
216
+ totalFields: totalFieldsTracked,
217
+ timestamp: Date.now(),
218
+ totalTimeMs: Date.now() - startTimeRef.current
219
+ });
220
+ }, [lastFocusedField, fieldsWithBlur, totalFieldsTracked, emit]);
221
+ const trackComplete = useCallback(() => {
222
+ emit({
223
+ type: "form_complete",
224
+ totalTimeMs: Date.now() - startTimeRef.current,
225
+ fieldTimes: fieldAnalytics,
226
+ timestamp: Date.now()
227
+ });
228
+ }, [fieldAnalytics, emit]);
229
+ const reset = useCallback(() => {
230
+ setFieldAnalytics(/* @__PURE__ */ new Map());
231
+ setLastFocusedField(null);
232
+ focusTimeRef.current.clear();
233
+ blurredFieldsRef.current.clear();
234
+ startTimeRef.current = Date.now();
235
+ }, []);
236
+ return { fieldAnalytics, completionRate, lastFocusedField, totalTimeMs, totalErrors, trackAbandon, trackComplete, reset };
237
+ }
238
+ function createEmptyAnalytics() {
239
+ return { focusCount: 0, totalTimeMs: 0, errorCount: 0, correctionCount: 0, firstFocusAt: null, lastBlurAt: null };
240
+ }
241
+
242
+ // src/lib/analytics/adapters/gtag.ts
243
+ function createGtagAdapter() {
244
+ return {
245
+ name: "gtag",
246
+ track(event, formId) {
247
+ const gtag = globalThis.gtag;
248
+ if (!gtag) return;
249
+ const params = { form_id: formId };
250
+ if ("field" in event) params.field_name = event.field;
251
+ switch (event.type) {
252
+ case "field_blur":
253
+ gtag("event", "form_field_interaction", { ...params, time_spent_ms: event.timeSpentMs });
254
+ break;
255
+ case "field_error":
256
+ gtag("event", "form_field_error", { ...params, error_message: event.error });
257
+ break;
258
+ case "form_abandon":
259
+ gtag("event", "form_abandon", { ...params, last_field: event.lastField, filled_fields: event.filledFields, total_time_ms: event.totalTimeMs });
260
+ break;
261
+ case "form_complete":
262
+ gtag("event", "form_complete", { ...params, total_time_ms: event.totalTimeMs });
263
+ break;
264
+ }
265
+ }
266
+ };
267
+ }
268
+
269
+ // src/lib/analytics/adapters/posthog.ts
270
+ function createPostHogAdapter() {
271
+ return {
272
+ name: "posthog",
273
+ track(event, formId) {
274
+ const posthog = globalThis.posthog;
275
+ if (!posthog) return;
276
+ const props = { form_id: formId, event_type: event.type };
277
+ if ("field" in event) props.field = event.field;
278
+ if (event.type === "field_blur") props.time_spent_ms = event.timeSpentMs;
279
+ if (event.type === "field_error") props.error = event.error;
280
+ if (event.type === "form_abandon") {
281
+ props.last_field = event.lastField;
282
+ props.filled_fields = event.filledFields;
283
+ props.total_time_ms = event.totalTimeMs;
284
+ }
285
+ if (event.type === "form_complete") props.total_time_ms = event.totalTimeMs;
286
+ posthog.capture(`form_${event.type}`, props);
287
+ }
288
+ };
289
+ }
290
+
291
+ // src/lib/analytics/adapters/umami.ts
292
+ function createUmamiAdapter(options) {
293
+ return {
294
+ name: "umami",
295
+ track(event, formId) {
296
+ const umami = globalThis.umami;
297
+ if (!umami) return;
298
+ const eventName = `form_${event.type}`;
299
+ const data = { formId, ..."field" in event ? { field: event.field } : {} };
300
+ if (event.type === "field_blur") data.timeSpentMs = event.timeSpentMs;
301
+ if (event.type === "field_error") data.error = event.error;
302
+ if (event.type === "form_abandon") {
303
+ data.lastField = event.lastField;
304
+ data.filledFields = event.filledFields;
305
+ data.totalTimeMs = event.totalTimeMs;
306
+ }
307
+ if (event.type === "form_complete") data.totalTimeMs = event.totalTimeMs;
308
+ umami.track(eventName, data);
309
+ }
310
+ };
311
+ }
312
+
313
+ // src/lib/analytics/adapters/yandex-metrika.ts
314
+ function createYandexMetrikaAdapter(counterId) {
315
+ return {
316
+ name: "yandex-metrika",
317
+ track(event, formId) {
318
+ const ym = globalThis.ym;
319
+ if (!ym) return;
320
+ const goalPrefix = formId ? `form_${formId}` : "form";
321
+ switch (event.type) {
322
+ case "field_focus":
323
+ ym(counterId, "reachGoal", `${goalPrefix}_field_focus`, { field: event.field });
324
+ break;
325
+ case "field_error":
326
+ ym(counterId, "reachGoal", `${goalPrefix}_field_error`, { field: event.field, error: event.error });
327
+ break;
328
+ case "form_abandon":
329
+ ym(counterId, "reachGoal", `${goalPrefix}_abandon`, {
330
+ lastField: event.lastField,
331
+ filledFields: event.filledFields,
332
+ totalTimeMs: event.totalTimeMs
333
+ });
334
+ break;
335
+ case "form_complete":
336
+ ym(counterId, "reachGoal", `${goalPrefix}_complete`, { totalTimeMs: event.totalTimeMs });
337
+ break;
338
+ }
339
+ }
340
+ };
341
+ }
342
+
343
+ export { AnalyticsPanel, createGtagAdapter, createPostHogAdapter, createUmamiAdapter, createYandexMetrikaAdapter, useFormAnalytics };
344
+ //# sourceMappingURL=chunk-K3J4L26K.js.map
345
+ //# sourceMappingURL=chunk-K3J4L26K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/analytics/analytics-panel.tsx","../src/lib/analytics/use-form-analytics.ts","../src/lib/analytics/adapters/gtag.ts","../src/lib/analytics/adapters/posthog.ts","../src/lib/analytics/adapters/umami.ts","../src/lib/analytics/adapters/yandex-metrika.ts"],"names":[],"mappings":"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","file":"chunk-K3J4L26K.js","sourcesContent":["'use client'\n\nimport { Box, Code, HStack, Text, VStack } from '@chakra-ui/react'\nimport type { ReactElement } from 'react'\nimport type { UseFormAnalyticsResult } from './types'\n\nexport interface AnalyticsPanelProps {\n /** Результат useFormAnalytics */\n analytics: UseFormAnalyticsResult\n /** Позиция панели */\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'\n}\n\n/**\n * Form.Analytics.Panel — dev-only панель с live-аналитикой формы.\n * Показывает: completion rate, время на полях, ошибки, corrections.\n */\nexport function AnalyticsPanel({ analytics, position = 'bottom-right' }: AnalyticsPanelProps): ReactElement {\n const positionStyles = {\n 'bottom-right': { bottom: 4, right: 4 },\n 'bottom-left': { bottom: 4, left: 4 },\n 'top-right': { top: 4, right: 4 },\n 'top-left': { top: 4, left: 4 },\n }\n\n const topFields = Array.from(analytics.fieldAnalytics.entries())\n .sort((a, b) => b[1].totalTimeMs - a[1].totalTimeMs)\n .slice(0, 5)\n\n return (\n <Box\n position=\"fixed\"\n {...positionStyles[position]}\n zIndex={9999}\n bg=\"gray.900\"\n color=\"white\"\n p={3}\n borderRadius=\"md\"\n fontSize=\"xs\"\n maxW=\"300px\"\n opacity={0.9}\n boxShadow=\"lg\"\n >\n <Text fontWeight=\"bold\" mb={2}>Form Analytics</Text>\n\n <HStack gap={4} mb={2}>\n <VStack gap={0} align=\"start\">\n <Text color=\"gray.400\">Completion</Text>\n <Text fontWeight=\"bold\" color={analytics.completionRate > 80 ? 'green.400' : 'yellow.400'}>\n {analytics.completionRate}%\n </Text>\n </VStack>\n <VStack gap={0} align=\"start\">\n <Text color=\"gray.400\">Errors</Text>\n <Text fontWeight=\"bold\" color={analytics.totalErrors > 0 ? 'red.400' : 'green.400'}>\n {analytics.totalErrors}\n </Text>\n </VStack>\n <VStack gap={0} align=\"start\">\n <Text color=\"gray.400\">Time</Text>\n <Text fontWeight=\"bold\">{Math.round(analytics.totalTimeMs / 1000)}s</Text>\n </VStack>\n </HStack>\n\n {topFields.length > 0 && (\n <>\n <Text color=\"gray.400\" mb={1}>Top fields by time:</Text>\n {topFields.map(([field, fa]) => (\n <HStack key={field} justify=\"space-between\">\n <Code fontSize=\"xs\" bg=\"transparent\" color=\"gray.300\">{field}</Code>\n <Text>{Math.round(fa.totalTimeMs / 1000)}s {fa.errorCount > 0 && `(${fa.errorCount} err)`}</Text>\n </HStack>\n ))}\n </>\n )}\n\n {analytics.lastFocusedField && (\n <Text color=\"gray.500\" mt={1}>Last: {analytics.lastFocusedField}</Text>\n )}\n </Box>\n )\n}\n","'use client'\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { FieldAnalytics, FormAnalyticsConfig, FormAnalyticsEvent, UseFormAnalyticsResult } from './types'\n\n/**\n * useFormAnalytics — трекинг поведения пользователя в форме.\n *\n * Отслеживает: focus/blur по полям, время на каждом поле, ошибки,\n * возвраты (corrections), процент заполнения, abandon/complete.\n */\nexport function useFormAnalytics(config?: FormAnalyticsConfig): UseFormAnalyticsResult {\n const { enabled = true, formId, adapters = [], trackCorrections = true } = config ?? {}\n\n const [fieldAnalytics, setFieldAnalytics] = useState<Map<string, FieldAnalytics>>(new Map())\n const [lastFocusedField, setLastFocusedField] = useState<string | null>(null)\n const startTimeRef = useRef(Date.now())\n const focusTimeRef = useRef<Map<string, number>>(new Map())\n const blurredFieldsRef = useRef<Set<string>>(new Set())\n\n // Отправить событие во все адаптеры + callbacks\n const emit = useCallback((event: FormAnalyticsEvent) => {\n if (!enabled) return\n for (const adapter of adapters) {\n try { adapter.track(event, formId) } catch {}\n }\n // Callbacks\n switch (event.type) {\n case 'field_focus': config?.onFieldFocus?.(event.field, event.timestamp); break\n case 'field_blur': config?.onFieldBlur?.(event.field, event.timestamp, event.timeSpentMs); break\n case 'field_error': config?.onFieldError?.(event.field, event.error); break\n case 'step_change': config?.onStepChange?.(event.from, event.to); break\n case 'form_abandon': config?.onAbandon?.(event.lastField, event.filledFields, event.totalFields); break\n case 'form_complete': config?.onComplete?.(event.totalTimeMs, event.fieldTimes); break\n }\n }, [enabled, adapters, formId, config])\n\n // Инициализация адаптеров\n useEffect(() => {\n if (!enabled) return\n for (const adapter of adapters) { try { adapter.init?.() } catch {} }\n return () => { for (const adapter of adapters) { try { adapter.destroy?.() } catch {} } }\n }, [enabled, adapters])\n\n // Трекинг focus на поле\n const trackFocus = useCallback((field: string) => {\n if (!enabled) return\n const now = Date.now()\n focusTimeRef.current.set(field, now)\n setLastFocusedField(field)\n\n setFieldAnalytics((prev) => {\n const next = new Map(prev)\n const existing = next.get(field) ?? createEmptyAnalytics()\n const isCorrection = trackCorrections && blurredFieldsRef.current.has(field)\n next.set(field, {\n ...existing,\n focusCount: existing.focusCount + 1,\n firstFocusAt: existing.firstFocusAt ?? now,\n correctionCount: existing.correctionCount + (isCorrection ? 1 : 0),\n })\n return next\n })\n\n emit({ type: 'field_focus', field, timestamp: now })\n if (trackCorrections && blurredFieldsRef.current.has(field)) {\n const analytics = fieldAnalytics.get(field)\n emit({ type: 'field_correction', field, timestamp: now, correctionCount: (analytics?.correctionCount ?? 0) + 1 })\n }\n }, [enabled, trackCorrections, fieldAnalytics, emit])\n\n // Трекинг blur\n const trackBlur = useCallback((field: string) => {\n if (!enabled) return\n const now = Date.now()\n const focusTime = focusTimeRef.current.get(field)\n const timeSpentMs = focusTime ? now - focusTime : 0\n blurredFieldsRef.current.add(field)\n\n setFieldAnalytics((prev) => {\n const next = new Map(prev)\n const existing = next.get(field) ?? createEmptyAnalytics()\n next.set(field, { ...existing, totalTimeMs: existing.totalTimeMs + timeSpentMs, lastBlurAt: now })\n return next\n })\n\n emit({ type: 'field_blur', field, timestamp: now, timeSpentMs })\n }, [enabled, emit])\n\n // Трекинг ошибки\n const trackError = useCallback((field: string, error: string) => {\n if (!enabled) return\n setFieldAnalytics((prev) => {\n const next = new Map(prev)\n const existing = next.get(field) ?? createEmptyAnalytics()\n next.set(field, { ...existing, errorCount: existing.errorCount + 1 })\n return next\n })\n emit({ type: 'field_error', field, error, timestamp: Date.now() })\n }, [enabled, emit])\n\n // Глобальный перехват focus/blur на инпутах формы\n useEffect(() => {\n if (!enabled || typeof document === 'undefined') return\n const handleFocus = (e: FocusEvent) => {\n const target = e.target as HTMLElement\n const name = target.getAttribute('name')\n if (name) trackFocus(name)\n }\n const handleBlur = (e: FocusEvent) => {\n const target = e.target as HTMLElement\n const name = target.getAttribute('name')\n if (name) trackBlur(name)\n }\n document.addEventListener('focusin', handleFocus, true)\n document.addEventListener('focusout', handleBlur, true)\n return () => {\n document.removeEventListener('focusin', handleFocus, true)\n document.removeEventListener('focusout', handleBlur, true)\n }\n }, [enabled, trackFocus, trackBlur])\n\n // Трекинг abandon при уходе со страницы\n useEffect(() => {\n if (!enabled || typeof window === 'undefined') return\n const handleBeforeUnload = () => {\n if (lastFocusedField && fieldAnalytics.size > 0) {\n emit({\n type: 'form_abandon',\n lastField: lastFocusedField,\n filledFields: fieldAnalytics.size,\n totalFields: fieldAnalytics.size, // приблизительно\n timestamp: Date.now(),\n totalTimeMs: Date.now() - startTimeRef.current,\n })\n }\n }\n window.addEventListener('beforeunload', handleBeforeUnload)\n return () => window.removeEventListener('beforeunload', handleBeforeUnload)\n }, [enabled, lastFocusedField, fieldAnalytics, emit])\n\n const totalTimeMs = Date.now() - startTimeRef.current\n const totalErrors = Array.from(fieldAnalytics.values()).reduce((sum, fa) => sum + fa.errorCount, 0)\n // Completion = поля с blur / общее количество полей с хотя бы одним фокусом\n const fieldsWithBlur = Array.from(fieldAnalytics.values()).filter((fa) => fa.lastBlurAt !== null).length\n const totalFieldsTracked = fieldAnalytics.size || 1\n const completionRate = Math.round((fieldsWithBlur / totalFieldsTracked) * 100)\n\n const trackAbandon = useCallback(() => {\n emit({\n type: 'form_abandon',\n lastField: lastFocusedField ?? '',\n filledFields: fieldsWithBlur,\n totalFields: totalFieldsTracked,\n timestamp: Date.now(),\n totalTimeMs: Date.now() - startTimeRef.current,\n })\n }, [lastFocusedField, fieldsWithBlur, totalFieldsTracked, emit])\n\n const trackComplete = useCallback(() => {\n emit({\n type: 'form_complete',\n totalTimeMs: Date.now() - startTimeRef.current,\n fieldTimes: fieldAnalytics,\n timestamp: Date.now(),\n })\n }, [fieldAnalytics, emit])\n\n const reset = useCallback(() => {\n setFieldAnalytics(new Map())\n setLastFocusedField(null)\n focusTimeRef.current.clear()\n blurredFieldsRef.current.clear()\n startTimeRef.current = Date.now()\n }, [])\n\n return { fieldAnalytics, completionRate, lastFocusedField, totalTimeMs, totalErrors, trackAbandon, trackComplete, reset }\n}\n\nfunction createEmptyAnalytics(): FieldAnalytics {\n return { focusCount: 0, totalTimeMs: 0, errorCount: 0, correctionCount: 0, firstFocusAt: null, lastBlurAt: null }\n}\n","import type { AnalyticsAdapter, FormAnalyticsEvent } from '../types'\n\n/** Адаптер для Google Analytics 4 (gtag) */\nexport function createGtagAdapter(): AnalyticsAdapter {\n return {\n name: 'gtag',\n track(event: FormAnalyticsEvent, formId?: string) {\n const gtag = (globalThis as { gtag?: (...args: unknown[]) => void }).gtag\n if (!gtag) return\n\n const params: Record<string, unknown> = { form_id: formId }\n if ('field' in event) params.field_name = event.field\n\n switch (event.type) {\n case 'field_blur':\n gtag('event', 'form_field_interaction', { ...params, time_spent_ms: event.timeSpentMs })\n break\n case 'field_error':\n gtag('event', 'form_field_error', { ...params, error_message: event.error })\n break\n case 'form_abandon':\n gtag('event', 'form_abandon', { ...params, last_field: event.lastField, filled_fields: event.filledFields, total_time_ms: event.totalTimeMs })\n break\n case 'form_complete':\n gtag('event', 'form_complete', { ...params, total_time_ms: event.totalTimeMs })\n break\n }\n },\n }\n}\n","import type { AnalyticsAdapter, FormAnalyticsEvent } from '../types'\n\n/** Адаптер для PostHog */\nexport function createPostHogAdapter(): AnalyticsAdapter {\n return {\n name: 'posthog',\n track(event: FormAnalyticsEvent, formId?: string) {\n const posthog = (globalThis as { posthog?: { capture: (name: string, props: Record<string, unknown>) => void } }).posthog\n if (!posthog) return\n\n const props: Record<string, unknown> = { form_id: formId, event_type: event.type }\n if ('field' in event) props.field = event.field\n if (event.type === 'field_blur') props.time_spent_ms = event.timeSpentMs\n if (event.type === 'field_error') props.error = event.error\n if (event.type === 'form_abandon') {\n props.last_field = event.lastField\n props.filled_fields = event.filledFields\n props.total_time_ms = event.totalTimeMs\n }\n if (event.type === 'form_complete') props.total_time_ms = event.totalTimeMs\n\n posthog.capture(`form_${event.type}`, props)\n },\n }\n}\n","import type { AnalyticsAdapter, FormAnalyticsEvent } from '../types'\n\n/** Адаптер для Umami Analytics (umami.is) */\nexport function createUmamiAdapter(options?: { websiteId?: string }): AnalyticsAdapter {\n return {\n name: 'umami',\n track(event: FormAnalyticsEvent, formId?: string) {\n const umami = (globalThis as { umami?: { track: (name: string, data: Record<string, unknown>) => void } }).umami\n if (!umami) return\n\n const eventName = `form_${event.type}`\n const data: Record<string, unknown> = { formId, ...('field' in event ? { field: event.field } : {}) }\n\n if (event.type === 'field_blur') data.timeSpentMs = event.timeSpentMs\n if (event.type === 'field_error') data.error = event.error\n if (event.type === 'form_abandon') {\n data.lastField = event.lastField\n data.filledFields = event.filledFields\n data.totalTimeMs = event.totalTimeMs\n }\n if (event.type === 'form_complete') data.totalTimeMs = event.totalTimeMs\n\n umami.track(eventName, data)\n },\n }\n}\n","import type { AnalyticsAdapter, FormAnalyticsEvent } from '../types'\n\n/** Адаптер для Яндекс Метрика (goals + params) */\nexport function createYandexMetrikaAdapter(counterId: number): AnalyticsAdapter {\n return {\n name: 'yandex-metrika',\n track(event: FormAnalyticsEvent, formId?: string) {\n const ym = (globalThis as { ym?: (id: number, action: string, goal: string, params?: Record<string, unknown>) => void }).ym\n if (!ym) return\n\n const goalPrefix = formId ? `form_${formId}` : 'form'\n\n switch (event.type) {\n case 'field_focus':\n ym(counterId, 'reachGoal', `${goalPrefix}_field_focus`, { field: event.field })\n break\n case 'field_error':\n ym(counterId, 'reachGoal', `${goalPrefix}_field_error`, { field: event.field, error: event.error })\n break\n case 'form_abandon':\n ym(counterId, 'reachGoal', `${goalPrefix}_abandon`, {\n lastField: event.lastField,\n filledFields: event.filledFields,\n totalTimeMs: event.totalTimeMs,\n })\n break\n case 'form_complete':\n ym(counterId, 'reachGoal', `${goalPrefix}_complete`, { totalTimeMs: event.totalTimeMs })\n break\n }\n },\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { createField, SelectionFieldLabel, FieldError, useAsyncSearch, FieldTooltip, getOptionLabel, useGroupedOptions, FieldWrapper, FieldLabel, useDeclarativeForm, useFormGroup, useResolvedFieldProps, getFieldErrors } from './chunk-HWVOFWAT.js';
1
+ import { createField, SelectionFieldLabel, FieldError, useAsyncSearch, FieldTooltip, getOptionLabel, useGroupedOptions, FieldWrapper, FieldLabel, useDeclarativeForm, useFormGroup, useResolvedFieldProps, getFieldErrors } from './chunk-XFWLD5EO.js';
2
2
  import { Field, Combobox, Spinner, Portal, useFilter, createListCollection, Fieldset, CheckboxGroup, HStack, Flex, CheckboxCard, Listbox, NativeSelect, RadioCard, RadioGroup, SegmentGroup, Select, TagsInput } from '@chakra-ui/react';
3
3
  import { useMemo, useCallback, useState, useRef, useEffect } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -780,7 +780,8 @@ function FieldCascadingSelect(props) {
780
780
  disabled: resolvedRest.disabled,
781
781
  readOnly: resolvedRest.readOnly,
782
782
  constraints: resolvedRest.constraints,
783
- options: resolvedRest.options
783
+ options: resolvedRest.options,
784
+ autocomplete: resolvedRest.autocomplete
784
785
  };
785
786
  const fullDependsOnPath = parentGroup ? `${parentGroup.name}.${dependsOn}` : dependsOn;
786
787
  const parentSelector = (state) => {
@@ -817,5 +818,5 @@ function FieldCascadingSelect(props) {
817
818
  FieldCascadingSelect.displayName = "FieldCascadingSelect";
818
819
 
819
820
  export { FieldAutocomplete, FieldCascadingSelect, FieldCheckboxCard, FieldCombobox, FieldListbox, FieldNativeSelect, FieldRadioCard, FieldRadioGroup, FieldSegmentedGroup, FieldSelect, FieldTags };
820
- //# sourceMappingURL=chunk-PJETA6YN.js.map
821
- //# sourceMappingURL=chunk-PJETA6YN.js.map
821
+ //# sourceMappingURL=chunk-MAYUFA5K.js.map
822
+ //# sourceMappingURL=chunk-MAYUFA5K.js.map