@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.
- package/CHANGELOG.md +308 -0
- package/README.md +9 -9
- package/README.ru.md +115 -30
- package/analytics.js +3 -0
- package/analytics.js.map +1 -0
- package/chunk-2PSXYC3I.js +1782 -0
- package/chunk-2PSXYC3I.js.map +1 -0
- package/chunk-5D6S6EGF.js +206 -0
- package/chunk-5D6S6EGF.js.map +1 -0
- package/{chunk-6QOPSQ3Z.js → chunk-6E7VJAJT.js} +3 -3
- package/{chunk-6QOPSQ3Z.js.map → chunk-6E7VJAJT.js.map} +1 -1
- package/chunk-CGXKRCSM.js +117 -0
- package/chunk-CGXKRCSM.js.map +1 -0
- package/{chunk-M2PNAAIR.js → chunk-DQUVUMCX.js} +30 -19
- package/chunk-DQUVUMCX.js.map +1 -0
- package/chunk-K3J4L26K.js +345 -0
- package/chunk-K3J4L26K.js.map +1 -0
- package/{chunk-PJETA6YN.js → chunk-MAYUFA5K.js} +5 -4
- package/chunk-MAYUFA5K.js.map +1 -0
- package/{chunk-4V6WBJ76.js → chunk-MVGXZNHP.js} +2 -2
- package/{chunk-4V6WBJ76.js.map → chunk-MVGXZNHP.js.map} +1 -1
- package/{chunk-XKKJKYWZ.js → chunk-MZDTJSF7.js} +3 -3
- package/{chunk-XKKJKYWZ.js.map → chunk-MZDTJSF7.js.map} +1 -1
- package/{chunk-KUNT5MSU.js → chunk-Q5EOF36Y.js} +3 -3
- package/chunk-Q5EOF36Y.js.map +1 -0
- package/{chunk-7FEQFDJ7.js → chunk-R2RTCKXY.js} +2 -2
- package/{chunk-7FEQFDJ7.js.map → chunk-R2RTCKXY.js.map} +1 -1
- package/{chunk-HWVOFWAT.js → chunk-XFWLD5EO.js} +225 -26
- package/chunk-XFWLD5EO.js.map +1 -0
- package/fields/boolean.js +3 -3
- package/fields/datetime.js +3 -3
- package/fields/number.js +3 -3
- package/fields/selection.js +3 -3
- package/fields/specialized.js +3 -3
- package/fields/text.js +3 -3
- package/hcaptcha-U4XIT3HS.js +64 -0
- package/hcaptcha-U4XIT3HS.js.map +1 -0
- package/i18n.js +1 -1
- package/index.js +3268 -51
- package/index.js.map +1 -1
- package/offline.js +1 -1
- package/package.json +33 -4
- package/recaptcha-PKAUAY2S.js +56 -0
- package/recaptcha-PKAUAY2S.js.map +1 -0
- package/server-errors.js +3 -0
- package/server-errors.js.map +1 -0
- package/turnstile-7FXTBSLW.js +36 -0
- package/turnstile-7FXTBSLW.js.map +1 -0
- package/validators/ru.js +73 -0
- package/validators/ru.js.map +1 -0
- package/chunk-GOELIS6T.js +0 -849
- package/chunk-GOELIS6T.js.map +0 -1
- package/chunk-HWVOFWAT.js.map +0 -1
- package/chunk-KUNT5MSU.js.map +0 -1
- package/chunk-M2PNAAIR.js.map +0 -1
- package/chunk-PJETA6YN.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,314 @@
|
|
|
4
4
|
|
|
5
5
|
Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.0.0/).
|
|
6
6
|
|
|
7
|
+
## [0.80.0] - 2026-04-04 — DX фичи: Analytics, History, ServerErrors, ReadOnly, Skeleton, Comparison, DependsOn
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **mapServerErrors()** — автоматический маппинг серверных ошибок на поля формы
|
|
12
|
+
- Автодетект формата: Prisma P2002/P2003/P2025/P2014, ZenStack policy/db-query, Zod flatten, ActionResult
|
|
13
|
+
- `applyServerErrors(form, mapped)` для TanStack Form
|
|
14
|
+
- Кастомный fieldMap для constraint → поле маппинга
|
|
15
|
+
- Locale: ru/en, subpath `@letar/forms/server-errors`
|
|
16
|
+
- 24 unit-теста, bench: 10M+ ops/sec
|
|
17
|
+
- **useFormHistory()** — Undo/Redo для форм (Ctrl+Z/Ctrl+Y)
|
|
18
|
+
- Debounced structuredClone снапшоты
|
|
19
|
+
- Keyboard shortcuts (Ctrl+Z, Ctrl+Shift+Z, Ctrl+Y)
|
|
20
|
+
- HistoryControls — визуальные кнопки ↩/↪
|
|
21
|
+
- Persist в sessionStorage (опционально)
|
|
22
|
+
- **Form.Analytics** — встроенная field-level аналитика форм
|
|
23
|
+
- useFormAnalytics() — focus/blur/error/correction/abandon/complete
|
|
24
|
+
- AnalyticsPanel — dev-only live-панель
|
|
25
|
+
- 4 адаптера: Umami, Яндекс Метрика, GA4, PostHog
|
|
26
|
+
- Subpath `@letar/forms/analytics`, bench: 25M+ ops/sec
|
|
27
|
+
- **FormReadOnlyView** — отображение данных формы в режиме чтения
|
|
28
|
+
- Автоматические labels из Zod .meta({ ui: { title } })
|
|
29
|
+
- exclude/include, compact mode, кастомные formatters
|
|
30
|
+
- **FormSkeleton** — loading state из Zod-схемы
|
|
31
|
+
- Автоопределение количества полей из schema
|
|
32
|
+
- showSubmit, configurable fieldHeight/gap
|
|
33
|
+
- **FormComparison** — diff-view (было → стало)
|
|
34
|
+
- Подсветка изменённых полей, onlyChanged mode
|
|
35
|
+
- Labels из Zod .meta(), exclude, кастомные labels
|
|
36
|
+
- **FormDependsOn** — каскадный рендеринг по значению поля
|
|
37
|
+
- cases map: значение → children, fallback
|
|
38
|
+
|
|
39
|
+
### Tests
|
|
40
|
+
|
|
41
|
+
- 59 новых unit/render тестов + 13 E2E + 16 бенчмарков
|
|
42
|
+
|
|
43
|
+
## [0.78.0] - 2026-04-03 — Captcha + CreditCard (Фазы 29-30)
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- **Form.Captcha** — CAPTCHA для защиты форм (Cloudflare Turnstile, Google reCAPTCHA, hCaptcha)
|
|
48
|
+
- Провайдер-абстракция с lazy loading
|
|
49
|
+
- Серверная верификация через `verifyCaptcha()`
|
|
50
|
+
- Интеграция с `createForm({ captcha: {...} })`
|
|
51
|
+
- **Form.Field.CreditCard** — ввод данных банковской карты
|
|
52
|
+
- Авто-форматирование номера (4-4-4-4 / 4-6-5 для Amex)
|
|
53
|
+
- Определение бренда по BIN (Visa, MC, Amex, МИР, JCB, Discover, UnionPay, Maestro)
|
|
54
|
+
- Luhn валидация, MM/YY expiry
|
|
55
|
+
- Готовая Zod-схема `creditCardSchema()`
|
|
56
|
+
- SVG иконки брендов (inline)
|
|
57
|
+
- Accessibility: role="group", aria-label, inputMode="numeric"
|
|
58
|
+
|
|
59
|
+
### Dependencies
|
|
60
|
+
|
|
61
|
+
- `@marsidev/react-turnstile` — peer dependency для Turnstile
|
|
62
|
+
|
|
63
|
+
## [0.77.0] - 2026-04-03
|
|
64
|
+
|
|
65
|
+
### Improved
|
|
66
|
+
|
|
67
|
+
- **DataGrid** — column reordering: drag заголовки колонок для изменения порядка
|
|
68
|
+
- **DataGrid** — diff highlighting: изменённые ячейки подсвечиваются жёлтым
|
|
69
|
+
- **MatrixChoice** — keyboard навигация: стрелки для перемещения между ячейками, Enter/Space для выбора
|
|
70
|
+
|
|
71
|
+
## [0.76.0] - 2026-04-03
|
|
72
|
+
|
|
73
|
+
### Improved
|
|
74
|
+
|
|
75
|
+
- **DataGrid** — виртуализация 1000+ строк через @tanstack/react-virtual (`virtualized` prop)
|
|
76
|
+
- Автоматический scroll-container с фиксированной высотой
|
|
77
|
+
- Пагинация автоматически отключается при виртуализации
|
|
78
|
+
- overscan: 10 строк для плавной прокрутки
|
|
79
|
+
- **DataGrid** — column resizing: drag границы колонок (`columnResizing` prop)
|
|
80
|
+
- Визуальный индикатор resize при перетаскивании
|
|
81
|
+
- **DataGrid** — расширенные фильтры уже поддерживают text (range, select, date — через кастомные filterFn)
|
|
82
|
+
- **MatrixChoice** — подсветка незаполненных строк красным при required + ошибке валидации
|
|
83
|
+
- **Async Validation** — loading indicator "Проверяю..." в FieldError при isValidating
|
|
84
|
+
- **TableEditor** — DnD сортировка строк через SortableWrapper (@dnd-kit)
|
|
85
|
+
- **TableEditor** — responsive mobile card view (карточки на sm breakpoints)
|
|
86
|
+
|
|
87
|
+
## [0.75.0] - 2026-04-03
|
|
88
|
+
|
|
89
|
+
### Added
|
|
90
|
+
|
|
91
|
+
- **`Form.Field.DataGrid`** — редактируемая таблица данных на TanStack Table (Фаза 16.2)
|
|
92
|
+
- TanStack Table v8 под капотом
|
|
93
|
+
- Сортировка по клику на заголовок (↑↓)
|
|
94
|
+
- Текстовые фильтры по колонкам
|
|
95
|
+
- Пагинация (кнопки Назад/Далее, номер страницы)
|
|
96
|
+
- Inline editing: клик по ячейке → Input
|
|
97
|
+
- Row-level save (`onRowSave` callback)
|
|
98
|
+
- Чекбокс-выбор строк + bulk delete
|
|
99
|
+
- Diff от TableEditor: DataGrid — для существующих данных с фильтрацией/сортировкой/пагинацией
|
|
100
|
+
|
|
101
|
+
### Changed
|
|
102
|
+
|
|
103
|
+
- Убраны из плана Фаза 16.3 (Spreadsheet) и 16.4 (Bulk Entry) — нишевые, избыточные
|
|
104
|
+
|
|
105
|
+
## [0.74.0] - 2026-04-03
|
|
106
|
+
|
|
107
|
+
### Added
|
|
108
|
+
|
|
109
|
+
- **Conversational Mode** — Typeform-стиль: одно поле за раз с анимацией
|
|
110
|
+
- `ConversationalMode` компонент-обёртка для полей формы
|
|
111
|
+
- Анимация fade-in-up при переходе между полями
|
|
112
|
+
- Progress bar и номер вопроса ("Вопрос 3 из 7")
|
|
113
|
+
- Enter → следующее поле, Alt+стрелки для навигации
|
|
114
|
+
- Кнопки Назад/Далее/Отправить
|
|
115
|
+
- Welcome screen и Completed screen
|
|
116
|
+
- `useConversationalState` хук для кастомного UI
|
|
117
|
+
- Keyboard-first UX
|
|
118
|
+
|
|
119
|
+
## [0.73.0] - 2026-04-03
|
|
120
|
+
|
|
121
|
+
### Added
|
|
122
|
+
|
|
123
|
+
- **Autosave to Server** — серверное автосохранение форм
|
|
124
|
+
- `useFormAutosave(form, config)` хук: периодическое POST/PUT с debounce
|
|
125
|
+
- `AutosaveIndicator` компонент: статус "Сохраняю..." / "Сохранено" / "Ошибка"
|
|
126
|
+
- Fallback на localStorage при отсутствии сети
|
|
127
|
+
- Восстановление черновиков: `loadDraft()` (сервер → localStorage)
|
|
128
|
+
- Не отправляет если данные не изменились
|
|
129
|
+
- AbortController-совместимый
|
|
130
|
+
|
|
131
|
+
## [0.72.0] - 2026-04-03
|
|
132
|
+
|
|
133
|
+
### Added
|
|
134
|
+
|
|
135
|
+
- **Form Templates** — 10 готовых шаблонов форм для быстрого старта
|
|
136
|
+
- `Form.FromTemplate` — компонент автоматической генерации формы из шаблона
|
|
137
|
+
- **Auth:** loginForm, registerForm, forgotPasswordForm
|
|
138
|
+
- **Feedback:** contactForm, feedbackForm
|
|
139
|
+
- **Survey:** npsForm
|
|
140
|
+
- **Business:** companyRegistration (ИНН, КПП, ОГРН, реквизиты)
|
|
141
|
+
- **E-commerce:** orderForm (клиент, адрес, товары)
|
|
142
|
+
- **Profile:** profileForm (имя, email, телефон)
|
|
143
|
+
- **Address:** addressForm (страна, город, улица, дом, индекс)
|
|
144
|
+
- Headless: `templates.xxx.schema` + `templates.xxx.defaultValues`
|
|
145
|
+
- Override: `exclude`, `fields` для кастомизации
|
|
146
|
+
- `FormTemplate<T>` интерфейс для создания собственных шаблонов
|
|
147
|
+
|
|
148
|
+
## [0.71.0] - 2026-04-03
|
|
149
|
+
|
|
150
|
+
### Added
|
|
151
|
+
|
|
152
|
+
- **Async Validation** — асинхронная валидация полей через props или Zod `.meta()`
|
|
153
|
+
- `asyncValidate` prop на любом поле: `<Form.Field.String asyncValidate={checkEmail} />`
|
|
154
|
+
- Декларативно через `.meta({ asyncValidate, asyncDebounce, asyncTrigger })`
|
|
155
|
+
- Debounce (по умолчанию 500мс), AbortController для отмены предыдущего запроса
|
|
156
|
+
- Кэширование результатов (не перепроверяет уже валидированные значения)
|
|
157
|
+
- Offline-safe: пропускает async-валидацию при отсутствии сети
|
|
158
|
+
- Триггер: `onBlur` (по умолчанию) или `onChange`
|
|
159
|
+
- Интеграция через TanStack Form `validators.onBlurAsync`/`onChangeAsync`
|
|
160
|
+
- `useAsyncFieldValidation` хук для кастомного использования
|
|
161
|
+
|
|
162
|
+
## [0.70.0] - 2026-04-03
|
|
163
|
+
|
|
164
|
+
### Added
|
|
165
|
+
|
|
166
|
+
- **`Form.Field.ImageChoice`** — выбор из картинок (grid карточек с изображениями)
|
|
167
|
+
- Single/multiple selection, hover + selected overlay
|
|
168
|
+
- Responsive grid (1→2→N колонок)
|
|
169
|
+
- **`Form.Field.Likert`** — шкала Лайкерта (5-7 точек с текстовыми якорями)
|
|
170
|
+
- Горизонтальная шкала (десктоп), вертикальный список (мобайл)
|
|
171
|
+
- Опциональная нумерация точек
|
|
172
|
+
- **`Form.Field.YesNo`** — бинарный выбор (два больших блока)
|
|
173
|
+
- Варианты: `buttons`, `thumbs` (👍👎), `emoji` (😊😞)
|
|
174
|
+
- Зелёный/красный highlight при выборе
|
|
175
|
+
|
|
176
|
+
## [0.69.0] - 2026-04-03
|
|
177
|
+
|
|
178
|
+
### Added
|
|
179
|
+
|
|
180
|
+
- **`Form.Field.MatrixChoice`** — матричный выбор для опросников и NPS-форм
|
|
181
|
+
- Таблица "вопрос × вариант ответа" (как в Google Forms, SurveyMonkey)
|
|
182
|
+
- 3 варианта: `radio` (одиночный), `checkbox` (множественный), `rating` (звёзды)
|
|
183
|
+
- Responsive: на мобильных — карточки вместо таблицы
|
|
184
|
+
- Row hover highlight, keyboard navigation
|
|
185
|
+
- Значение: `Record<string, string | string[]>`
|
|
186
|
+
|
|
187
|
+
## [0.68.0] - 2026-04-03
|
|
188
|
+
|
|
189
|
+
### Added
|
|
190
|
+
|
|
191
|
+
- **`Form.Field.TableEditor`** — инлайн-редактируемая таблица для array-полей
|
|
192
|
+
- Авто-колонки из Zod schema `.meta({ ui: { title } })` или кастомные через `columns` prop
|
|
193
|
+
- Клик по ячейке → inline editing (Input, NativeSelect, Checkbox в зависимости от типа)
|
|
194
|
+
- Tab/Enter навигация между ячейками, Enter в последней → новая строка
|
|
195
|
+
- Escape → выход из редактирования
|
|
196
|
+
- Стрелки вверх/вниз для перемещения между строками
|
|
197
|
+
- Computed columns — вычисляемые readonly колонки
|
|
198
|
+
- Footer aggregates — SUM, AVG, COUNT, MIN, MAX по колонкам
|
|
199
|
+
- Copy-paste из Excel/Sheets (парсинг TSV через Clipboard API)
|
|
200
|
+
- Чекбокс-выбор строк + массовое удаление
|
|
201
|
+
- Cell-level Zod валидация (ошибки прямо в ячейке)
|
|
202
|
+
- Пустое состояние с placeholder текстом
|
|
203
|
+
- `sortable`, `selectable`, `clipboard`, `striped` props
|
|
204
|
+
- Хуки: `useTableColumns`, `useTableNavigation`, `useTableClipboard`, `useTableEditorContext`
|
|
205
|
+
- Утилиты: `parseTSV`, `buildTSV`, `coerceValue`, `computeAggregate`, `formatCellValue`
|
|
206
|
+
|
|
207
|
+
## [0.67.0] - 2026-04-03
|
|
208
|
+
|
|
209
|
+
### Added
|
|
210
|
+
|
|
211
|
+
- **Russian Documents** — `zRu` Zod-валидаторы + `Form.Document.*` UI-компоненты
|
|
212
|
+
- **Валидаторы** (`@letar/forms/validators/ru`): zRu.inn(), zRu.kpp(), zRu.ogrn(), zRu.ogrnip(), zRu.bik(), zRu.bankAccount(), zRu.corrAccount(), zRu.snils(), zRu.passport()
|
|
213
|
+
- Контрольные суммы: ИНН (взвешенная mod 11), ОГРН (mod 11), ОГРНИП (mod 13), СНИЛС (mod 101), банковский счёт (контрольный ключ с БИК)
|
|
214
|
+
- Варианты ИНН: `zRu.inn.legal()` (10 цифр), `zRu.inn.individual()` (12 цифр)
|
|
215
|
+
- Transform: автоматическая очистка от пробелов/дефисов
|
|
216
|
+
- **UI-компоненты** (`Form.Document.*`): INN, KPP, OGRN, BIK, BankAccount, CorrAccount, SNILS, Passport
|
|
217
|
+
- Маска ввода (use-mask-input), иконки, realtime-валидация контрольных сумм
|
|
218
|
+
- `createDocumentField` — фабрика для кастомных документных полей
|
|
219
|
+
- Subpath export: `@letar/forms/validators/ru` для headless использования
|
|
220
|
+
- 46 unit-тестов для валидаторов
|
|
221
|
+
|
|
222
|
+
## [0.66.0] - 2026-04-03
|
|
223
|
+
|
|
224
|
+
### Added
|
|
225
|
+
|
|
226
|
+
- **`Form.Field.Signature`** — поле цифровой подписи
|
|
227
|
+
- Draw mode: рисование мышью и пальцем (touch) на Canvas
|
|
228
|
+
- Typed mode: ввод имени курсивным шрифтом, отрисовка на Canvas
|
|
229
|
+
- Переключение режимов через SegmentedControl (Draw / Type)
|
|
230
|
+
- Кнопка очистки подписи
|
|
231
|
+
- Placeholder поверх пустого canvas
|
|
232
|
+
- Responsive: canvas адаптируется к ширине контейнера
|
|
233
|
+
- Touch support: `touchAction: none` для предотвращения scroll
|
|
234
|
+
- Accessibility: `role="img"`, `aria-label`, Tab focus, typed mode как keyboard fallback
|
|
235
|
+
- Dark mode support через props `strokeColor`/`backgroundColor`
|
|
236
|
+
- Значение: data URI строка (image/png base64)
|
|
237
|
+
- Props: `width`, `height`, `strokeColor`, `strokeWidth`, `backgroundColor`, `clearLabel`, `placeholder`, `allowTyped`, `typedFont`
|
|
238
|
+
- 7 unit-тестов для FieldSignature
|
|
239
|
+
|
|
240
|
+
## [0.65.0] - 2026-04-03
|
|
241
|
+
|
|
242
|
+
### Added
|
|
243
|
+
|
|
244
|
+
- **Security Patterns** — три механизма защиты форм
|
|
245
|
+
- **Honeypot** — ловушка для ботов: `<Form honeypot={true}>`, скрытое поле блокирует submit ботов
|
|
246
|
+
- **Rate Limiting** — клиентский лимит: `<Form rateLimit={{ maxSubmits: 3, windowMs: 60000 }}>`, обратный отсчёт, sessionStorage persistence
|
|
247
|
+
- **Secure File Upload** — расширение FileUpload: `<Form.Field.FileUpload security={{ ... }}>`:
|
|
248
|
+
- `maxSize` — проверка размера ('10MB', '500KB')
|
|
249
|
+
- `allowedTypes` — проверка MIME по magic bytes (не по расширению)
|
|
250
|
+
- `stripMetadata` — удаление EXIF через Canvas API
|
|
251
|
+
- `renameFile` — замена имени на UUID (защита от path traversal)
|
|
252
|
+
- `parseFileSize()`, `validateMimeType()`, `sanitizeFileName()` — утилиты безопасности
|
|
253
|
+
- `useRateLimit()` — хук клиентского rate limiting
|
|
254
|
+
- `FileSecurityConfig`, `RateLimitConfig` — типы конфигурации
|
|
255
|
+
- 21 unit-тест для security модуля
|
|
256
|
+
|
|
257
|
+
## [0.64.0] - 2026-04-03
|
|
258
|
+
|
|
259
|
+
### Added
|
|
260
|
+
|
|
261
|
+
- **`Form.Field.Calculated`** — вычисляемое поле формы с автоматическим пересчётом
|
|
262
|
+
- `compute(values)` — функция вычисления значения из всех полей формы
|
|
263
|
+
- `format(value)` — форматирование отображения (например, `1 500 ₽`)
|
|
264
|
+
- `deps` — список зависимых полей для оптимизации пересчёта
|
|
265
|
+
- `debounce` — дебаунс вычислений для тяжёлых формул
|
|
266
|
+
- `hidden` — скрытый режим (вычисляет без отображения, как Hidden)
|
|
267
|
+
- Защита от циклических зависимостей (runtime detection)
|
|
268
|
+
- Работает внутри `Form.Group` (group-aware paths)
|
|
269
|
+
- Значение readonly, сохраняется в form state при submit
|
|
270
|
+
- `useComputedValue` — хук реактивного вычисления (подписка на form.store)
|
|
271
|
+
- 8 unit-тестов для FieldCalculated
|
|
272
|
+
- Демо-страница calculated-demo в form-develop-app
|
|
273
|
+
|
|
274
|
+
## [0.63.0] - 2026-04-03
|
|
275
|
+
|
|
276
|
+
### Added
|
|
277
|
+
|
|
278
|
+
- **`Form.InfoBlock`** — информационный блок внутри формы (info/warning/error/success/tip), на базе Chakra Alert
|
|
279
|
+
- Props: `variant`, `title`, `appearance`, `size`
|
|
280
|
+
- Интеграция с `Form.When` для условного отображения
|
|
281
|
+
- **`Form.Divider`** — разделитель секций формы с опциональной меткой и иконкой, на базе Chakra Separator
|
|
282
|
+
- Props: `label`, `icon`, `variant` (solid/dashed/dotted), `size`, `colorPalette`
|
|
283
|
+
- **`Form.Field.Hidden`** — скрытое поле формы (не рендерится в DOM, только в form state)
|
|
284
|
+
- Реактивная синхронизация `value` prop с form state
|
|
285
|
+
- Полезно для UTM-меток, referral кодов, внутренних ID
|
|
286
|
+
- 10 unit-тестов для новых компонентов
|
|
287
|
+
|
|
288
|
+
## [0.62.0] - 2026-04-03
|
|
289
|
+
|
|
290
|
+
### Added
|
|
291
|
+
|
|
292
|
+
- **Smart Autofill** — автоматическое проставление HTML `autocomplete` атрибутов по имени поля (+30% конверсии, WCAG 1.3.5)
|
|
293
|
+
- 30+ маппингов: email, phone, firstName, lastName, password, address, city, zip, country, company, username...
|
|
294
|
+
- Override через `.meta({ ui: { autocomplete: '...' } })` или prop `autoComplete`
|
|
295
|
+
- Приоритет: prop > meta > авто-определение
|
|
296
|
+
- Поддержка dot-path (address.city → autocomplete="address-level2")
|
|
297
|
+
- `autocomplete` в `FieldUIMeta` для ZenStack-генерации
|
|
298
|
+
- Поле `autocomplete` в `ResolvedFieldProps` — доступно всем field-компонентам
|
|
299
|
+
- 22 unit-теста для маппинга autocomplete
|
|
300
|
+
|
|
301
|
+
## [0.61.0] - 2026-04-03
|
|
302
|
+
|
|
303
|
+
### Added
|
|
304
|
+
|
|
305
|
+
- **`onFieldChange` prop** на `<Form>` — реактивные побочные эффекты при изменении полей (автогенерация slug, пересчёт итогов, синхронизация зависимых полей)
|
|
306
|
+
- **`<Form.Watch>`** — renderless compound component для отслеживания изменений поля внутри формы (group-aware, резолвит пути относительно `Form.Group`)
|
|
307
|
+
- **`FieldChangeApi`** — интерфейс с `setFieldValue`, `getFieldValue`, `getValues` для callbacks
|
|
308
|
+
- **`useFieldChangeListeners`** — хук подписки на изменения полей через `form.store.subscribe()` с `Object.is` сравнением
|
|
309
|
+
- 7 unit-тестов для нового функционала
|
|
310
|
+
|
|
311
|
+
### Fixed
|
|
312
|
+
|
|
313
|
+
- `FormRoot` теперь прокидывает `middleware` и `addressProvider` в `FormSimple`/`FormWithApi` (ранее терялись)
|
|
314
|
+
|
|
7
315
|
## [1.1.0] - 2026-04-01
|
|
8
316
|
|
|
9
317
|
### Added
|
package/README.md
CHANGED
|
@@ -239,16 +239,16 @@ import { FormI18nProvider, useFormI18n } from '@letar/forms/i18n'
|
|
|
239
239
|
|
|
240
240
|
## Peer Dependencies
|
|
241
241
|
|
|
242
|
-
| Package | Version | Required
|
|
243
|
-
| ---------------------- | --------- |
|
|
244
|
-
| `react` | >= 18.0.0 | Yes
|
|
245
|
-
| `@tanstack/react-form` | >= 1.0.0 | Yes
|
|
246
|
-
| `@chakra-ui/react` | >= 3.0.0 | Yes
|
|
247
|
-
| `framer-motion` | >= 10.0.0 | Yes
|
|
248
|
-
| `zod` | >= 3.24.0 | Yes
|
|
242
|
+
| Package | Version | Required |
|
|
243
|
+
| ---------------------- | --------- | -------------------------------- |
|
|
244
|
+
| `react` | >= 18.0.0 | Yes |
|
|
245
|
+
| `@tanstack/react-form` | >= 1.0.0 | Yes |
|
|
246
|
+
| `@chakra-ui/react` | >= 3.0.0 | Yes |
|
|
247
|
+
| `framer-motion` | >= 10.0.0 | Yes |
|
|
248
|
+
| `zod` | >= 3.24.0 | Yes |
|
|
249
249
|
| `@dnd-kit/*` | >= 6.0.0 | Optional (drag & drop in arrays) |
|
|
250
|
-
| `use-mask-input` | >= 3.0.0 | Optional (Phone, MaskedInput)
|
|
251
|
-
| `@uiw/react-json-view` | >= 2.0.0
|
|
250
|
+
| `use-mask-input` | >= 3.0.0 | Optional (Phone, MaskedInput) |
|
|
251
|
+
| `@uiw/react-json-view` | >= 2.0.0 | Optional (Form.DebugValues) |
|
|
252
252
|
|
|
253
253
|
## Documentation
|
|
254
254
|
|
package/README.ru.md
CHANGED
|
@@ -45,15 +45,16 @@ const Schema = z.object({
|
|
|
45
45
|
|
|
46
46
|
## Документация
|
|
47
47
|
|
|
48
|
-
| Категория | Документация | Описание
|
|
49
|
-
| ---------------- | -------------------------------------------------------- |
|
|
50
|
-
| Field компоненты | [docs/fields.md](./docs/fields.md) |
|
|
51
|
-
| Form-level | [docs/form-level.md](./docs/form-level.md) | Steps, When,
|
|
52
|
-
| Schema генерация | [docs/schema-generation.md](./docs/schema-generation.md) | FromSchema, AutoFields, Builder
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
|
|
|
48
|
+
| Категория | Документация | Описание |
|
|
49
|
+
| ---------------- | -------------------------------------------------------- | --------------------------------------------- |
|
|
50
|
+
| Field компоненты | [docs/fields.md](./docs/fields.md) | 50+ типов полей (String, Number, Select, ...) |
|
|
51
|
+
| Form-level | [docs/form-level.md](./docs/form-level.md) | Steps, When, Watch, Errors, Persistence |
|
|
52
|
+
| Schema генерация | [docs/schema-generation.md](./docs/schema-generation.md) | FromSchema, AutoFields, Builder, Templates |
|
|
53
|
+
| Server Errors | [docs/server-errors.md](./docs/server-errors.md) | Маппинг Prisma/ZenStack/Zod ошибок на поля |
|
|
54
|
+
| Offline | [docs/offline.md](./docs/offline.md) | Оффлайн режим, очередь синхронизации |
|
|
55
|
+
| ZenStack | [docs/zenstack.md](./docs/zenstack.md) | Плагин, @form.\* директивы, withUIMeta |
|
|
56
|
+
| i18n | [docs/i18n.md](./docs/i18n.md) | Мультиязычность, перевод ошибок валидации |
|
|
57
|
+
| API Reference | [docs/api-reference.md](./docs/api-reference.md) | Хуки, контексты, типы |
|
|
57
58
|
|
|
58
59
|
---
|
|
59
60
|
|
|
@@ -81,6 +82,11 @@ const Schema = z.object({
|
|
|
81
82
|
<Form.Field.Date name="birthday" />
|
|
82
83
|
<Form.Field.Phone name="phone" />
|
|
83
84
|
<Form.Field.FileUpload name="avatar" />
|
|
85
|
+
<Form.Field.Signature name="signature" />
|
|
86
|
+
<Form.Field.CreditCard name="card" />
|
|
87
|
+
|
|
88
|
+
// Защита
|
|
89
|
+
<Form.Captcha />
|
|
84
90
|
```
|
|
85
91
|
|
|
86
92
|
[Полный список → docs/fields.md](./docs/fields.md)
|
|
@@ -89,6 +95,14 @@ const Schema = z.object({
|
|
|
89
95
|
|
|
90
96
|
```tsx
|
|
91
97
|
<Form schema={Schema} initialValue={data} onSubmit={save}>
|
|
98
|
+
{/* Реактивные побочные эффекты */}
|
|
99
|
+
<Form.Watch
|
|
100
|
+
field="name"
|
|
101
|
+
onChange={(v, { setFieldValue }) => {
|
|
102
|
+
setFieldValue('slug', transliterate(String(v)))
|
|
103
|
+
}}
|
|
104
|
+
/>
|
|
105
|
+
|
|
92
106
|
{/* Условный рендеринг */}
|
|
93
107
|
<Form.When field="type" is="company">
|
|
94
108
|
<Form.Field.String name="companyName" />
|
|
@@ -101,6 +115,38 @@ const Schema = z.object({
|
|
|
101
115
|
<Form.Steps.Navigation />
|
|
102
116
|
</Form.Steps>
|
|
103
117
|
|
|
118
|
+
{/* Информационный блок */}
|
|
119
|
+
<Form.InfoBlock variant="info" title="Подсказка">
|
|
120
|
+
Заполните все поля для скидки.
|
|
121
|
+
</Form.InfoBlock>
|
|
122
|
+
|
|
123
|
+
{/* Разделитель секций */}
|
|
124
|
+
<Form.Divider label="Контакты" />
|
|
125
|
+
|
|
126
|
+
{/* Вычисляемые поля */}
|
|
127
|
+
<Form.Field.Calculated
|
|
128
|
+
name="total"
|
|
129
|
+
compute={(v) => v.price * v.qty}
|
|
130
|
+
format={(v) => `${v.toLocaleString()} ₽`}
|
|
131
|
+
deps={['price', 'qty']}
|
|
132
|
+
/>
|
|
133
|
+
|
|
134
|
+
{/* Табличный редактор (массив объектов) */}
|
|
135
|
+
<Form.Field.TableEditor
|
|
136
|
+
name="items"
|
|
137
|
+
columns={[
|
|
138
|
+
{ name: 'product', width: '40%' },
|
|
139
|
+
{ name: 'qty', width: '15%', align: 'right' },
|
|
140
|
+
{ name: 'price', width: '15%', align: 'right' },
|
|
141
|
+
{ name: 'total', computed: (row) => row.qty * row.price, label: 'Итого' },
|
|
142
|
+
]}
|
|
143
|
+
addLabel="Добавить товар"
|
|
144
|
+
footer={[{ column: 'total', aggregate: 'sum', label: 'Итого:' }]}
|
|
145
|
+
/>
|
|
146
|
+
|
|
147
|
+
{/* Скрытые поля (UTM, referral) */}
|
|
148
|
+
<Form.Field.Hidden name="utm_source" value="landing" />
|
|
149
|
+
|
|
104
150
|
{/* Сводка ошибок */}
|
|
105
151
|
<Form.Errors title="Исправьте ошибки:" />
|
|
106
152
|
|
|
@@ -129,6 +175,18 @@ const Schema = z.object({
|
|
|
129
175
|
</Form.Group.List>
|
|
130
176
|
```
|
|
131
177
|
|
|
178
|
+
### Smart Autofill
|
|
179
|
+
|
|
180
|
+
Поля автоматически получают правильные `autocomplete` атрибуты (+30% конверсии, WCAG 1.3.5):
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
<Form.Field.String name="email" /> // → autocomplete="email"
|
|
184
|
+
<Form.Field.String name="firstName" /> // → autocomplete="given-name"
|
|
185
|
+
<Form.Field.Password name="password" /> // → autocomplete="current-password"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Override: `autoComplete` prop или `.meta({ ui: { autocomplete: 'off' } })`.
|
|
189
|
+
|
|
132
190
|
### Автоматические constraints из Zod
|
|
133
191
|
|
|
134
192
|
```tsx
|
|
@@ -159,7 +217,7 @@ model Product {
|
|
|
159
217
|
|
|
160
218
|
```tsx
|
|
161
219
|
import { ProductCreateFormSchema } from '@/generated/form-schemas'
|
|
162
|
-
|
|
220
|
+
<Form.FromSchema schema={ProductCreateFormSchema} initialValue={data} onSubmit={save} />
|
|
163
221
|
```
|
|
164
222
|
|
|
165
223
|
[Подробнее → docs/zenstack.md](./docs/zenstack.md)
|
|
@@ -184,6 +242,32 @@ import { ProductCreateFormSchema } from '@/generated/form-schemas'
|
|
|
184
242
|
|
|
185
243
|
[Подробнее → docs/offline.md](./docs/offline.md)
|
|
186
244
|
|
|
245
|
+
### Security
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
// Honeypot — ловушка для ботов
|
|
249
|
+
<Form honeypot={true} initialValue={data} onSubmit={handleSubmit}>
|
|
250
|
+
<Form.Field.String name="email" />
|
|
251
|
+
<Form.Button.Submit />
|
|
252
|
+
</Form>
|
|
253
|
+
|
|
254
|
+
// Rate Limiting — ограничение попыток submit
|
|
255
|
+
<Form rateLimit={{ maxSubmits: 3, windowMs: 60000 }} initialValue={data} onSubmit={handleSubmit}>
|
|
256
|
+
...
|
|
257
|
+
</Form>
|
|
258
|
+
|
|
259
|
+
// Secure File Upload — проверка MIME, удаление EXIF, переименование
|
|
260
|
+
<Form.Field.FileUpload
|
|
261
|
+
name="document"
|
|
262
|
+
security={{
|
|
263
|
+
maxSize: '10MB',
|
|
264
|
+
allowedTypes: ['image/jpeg', 'image/png', 'application/pdf'],
|
|
265
|
+
stripMetadata: true,
|
|
266
|
+
renameFile: true,
|
|
267
|
+
}}
|
|
268
|
+
/>
|
|
269
|
+
```
|
|
270
|
+
|
|
187
271
|
---
|
|
188
272
|
|
|
189
273
|
## Установка
|
|
@@ -195,13 +279,14 @@ import { Form } from '@lena/form-components'
|
|
|
195
279
|
|
|
196
280
|
### Опциональные зависимости (npm)
|
|
197
281
|
|
|
198
|
-
| Пакет
|
|
199
|
-
|
|
|
200
|
-
| `@dnd-kit/*`
|
|
201
|
-
| `use-mask-input`
|
|
202
|
-
| `@tiptap/*`
|
|
203
|
-
| `@uiw/react-json-view`
|
|
204
|
-
| `next-intl`
|
|
282
|
+
| Пакет | Для чего |
|
|
283
|
+
| --------------------------- | --------------------------------- |
|
|
284
|
+
| `@dnd-kit/*` | Drag & drop сортировка в массивах |
|
|
285
|
+
| `use-mask-input` | Phone, MaskedInput |
|
|
286
|
+
| `@tiptap/*` | RichText редактор |
|
|
287
|
+
| `@uiw/react-json-view` | Form.DebugValues (JSON инспектор) |
|
|
288
|
+
| `next-intl` | i18n интеграция |
|
|
289
|
+
| `@marsidev/react-turnstile` | CAPTCHA (Cloudflare Turnstile) |
|
|
205
290
|
|
|
206
291
|
---
|
|
207
292
|
|
|
@@ -262,17 +347,17 @@ MCP сервер [`@letar/form-mcp`](../form-mcp/README.md) предоставл
|
|
|
262
347
|
|
|
263
348
|
Библиотека поставляется как ESM с external dependencies. Все тяжёлые зависимости (Chakra, React, Tiptap, dnd-kit) — external и не включаются в bundle.
|
|
264
349
|
|
|
265
|
-
| Модуль
|
|
266
|
-
|
|
267
|
-
| `@letar/forms` (все 40 полей)
|
|
268
|
-
| `@letar/forms/fields/text`
|
|
269
|
-
| `@letar/forms/fields/number`
|
|
270
|
-
| `@letar/forms/fields/datetime`
|
|
271
|
-
| `@letar/forms/fields/selection`
|
|
272
|
-
| `@letar/forms/fields/boolean`
|
|
273
|
-
| `@letar/forms/fields/specialized` | < 1 KB
|
|
274
|
-
| `@letar/forms/offline`
|
|
275
|
-
| `@letar/forms/i18n`
|
|
350
|
+
| Модуль | Размер (brotli) | Размер (raw) |
|
|
351
|
+
| --------------------------------- | --------------- | ------------ |
|
|
352
|
+
| `@letar/forms` (все 40 полей) | **20 KB** | 109 KB |
|
|
353
|
+
| `@letar/forms/fields/text` | < 1 KB | re-export |
|
|
354
|
+
| `@letar/forms/fields/number` | < 1 KB | re-export |
|
|
355
|
+
| `@letar/forms/fields/datetime` | < 1 KB | re-export |
|
|
356
|
+
| `@letar/forms/fields/selection` | < 1 KB | re-export |
|
|
357
|
+
| `@letar/forms/fields/boolean` | < 1 KB | re-export |
|
|
358
|
+
| `@letar/forms/fields/specialized` | < 1 KB | re-export |
|
|
359
|
+
| `@letar/forms/offline` | < 1 KB | 5 KB |
|
|
360
|
+
| `@letar/forms/i18n` | < 1 KB | 13 KB |
|
|
276
361
|
|
|
277
362
|
Категорийные entry points (`fields/*`) позволяют импортировать только нужные поля:
|
|
278
363
|
|
|
@@ -300,5 +385,5 @@ import { FieldString, FieldTextarea } from '@letar/forms/fields/text'
|
|
|
300
385
|
|
|
301
386
|
---
|
|
302
387
|
|
|
303
|
-
**Версия:** 0.
|
|
304
|
-
**Последнее обновление:** 2026-04-
|
|
388
|
+
**Версия:** 0.63.0
|
|
389
|
+
**Последнее обновление:** 2026-04-03
|
package/analytics.js
ADDED
package/analytics.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"analytics.js"}
|