@letar/forms 1.0.3 → 1.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,29 @@
4
4
 
5
5
  Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.0.0/).
6
6
 
7
+ ## [1.1.0] - 2026-04-01
8
+
9
+ ### Added
10
+
11
+ - **size-limit** CI: bundle size проверка перед каждым npm publish (20 KB brotli full)
12
+ - **Категорийные entry points**: `@letar/forms/fields/{text,number,datetime,selection,boolean,specialized}`
13
+ - **Бенчмарк ре-рендеров**: 10 полей, ввод в одно → 0 лишних рендеров у остальных
14
+ - **FieldErrorBoundary**: ErrorBoundary для каждого field-компонента (fallback при ошибке рендеринга)
15
+ - **Type-тесты**: DeepKeys, DeepValue, useTypedFormSubscribe (vitest expectTypeOf)
16
+ - `loadingText` prop в `Form.Button.Submit` для кастомного текста при загрузке
17
+ - `City` и `sortable` в FormFieldComponents/FormGroupListComponent типах
18
+
19
+ ### Fixed
20
+
21
+ - Race condition в Form.Steps — все шаги получали index=0
22
+ - Число полей "49" → "40" во всех 12 статьях и README
23
+
24
+ ### Changed
25
+
26
+ - tsup entry points расширены с 3 до 9 (code splitting для categories)
27
+ - Bundle Size секция в README с актуальными метриками
28
+ - `package.publish.json` exports map с 6 category entry points
29
+
7
30
  ## [0.58.0] - 2026-03-31
8
31
 
9
32
  ### Added
package/README.ru.md ADDED
@@ -0,0 +1,304 @@
1
+ # @lena/form-components
2
+
3
+ Переиспользуемая UI-библиотека компонентов форм на базе TanStack Form для монорепозитория Lena.
4
+
5
+ [English documentation](./README.en.md)
6
+
7
+ ## Quick Start
8
+
9
+ ```tsx
10
+ import { Form } from '@lena/form-components'
11
+ import { z } from 'zod/v4'
12
+
13
+ const Schema = z.object({
14
+ title: z.string().min(2).meta({ ui: { title: 'Название', placeholder: 'Введите...' } }),
15
+ rating: z.number().min(0).max(10).meta({ ui: { title: 'Рейтинг' } }),
16
+ })
17
+
18
+ <Form schema={Schema} initialValue={{ title: '', rating: 5 }} onSubmit={save}>
19
+ <Form.Field.String name="title" />
20
+ <Form.Field.Number name="rating" />
21
+ <Form.Button.Submit>Сохранить</Form.Button.Submit>
22
+ </Form>
23
+ ```
24
+
25
+ **Или полная автогенерация:**
26
+
27
+ ```tsx
28
+ <Form.FromSchema schema={Schema} initialValue={data} onSubmit={handleSubmit} submitLabel="Создать" />
29
+ ```
30
+
31
+ ---
32
+
33
+ ## Философия: Отделение вёрстки от логики
34
+
35
+ | Аспект | Где определяется | Как используется в JSX |
36
+ | ----------------- | -------------------------- | ------------------------------- |
37
+ | **Валидация** | Zod схема | `schema={Schema}` |
38
+ | **UI метаданные** | Zod `.meta({ ui: {...} })` | Автоматически из схемы |
39
+ | **Структура** | TypeScript типы | `initialValue={data}` |
40
+ | **Вёрстка** | JSX | `<HStack>`, `<VStack>`, `<Box>` |
41
+
42
+ **Результат:** JSX содержит только вёрстку и имена полей. Вся логика живёт в схеме.
43
+
44
+ ---
45
+
46
+ ## Документация
47
+
48
+ | Категория | Документация | Описание |
49
+ | ---------------- | -------------------------------------------------------- | -------------------------------------------- |
50
+ | Field компоненты | [docs/fields.md](./docs/fields.md) | 40 типов полей (String, Number, Select, ...) |
51
+ | Form-level | [docs/form-level.md](./docs/form-level.md) | Steps, When, Errors, Middleware, Persistence |
52
+ | Schema генерация | [docs/schema-generation.md](./docs/schema-generation.md) | FromSchema, AutoFields, Builder |
53
+ | Offline | [docs/offline.md](./docs/offline.md) | Оффлайн режим, очередь синхронизации |
54
+ | ZenStack | [docs/zenstack.md](./docs/zenstack.md) | Плагин, @form.\* директивы, withUIMeta |
55
+ | i18n | [docs/i18n.md](./docs/i18n.md) | Мультиязычность, перевод ошибок валидации |
56
+ | API Reference | [docs/api-reference.md](./docs/api-reference.md) | Хуки, контексты, типы |
57
+
58
+ ---
59
+
60
+ ## Основные возможности
61
+
62
+ ### 40+ Field компонентов
63
+
64
+ ```tsx
65
+ // Текстовые
66
+ <Form.Field.String name="title" />
67
+ <Form.Field.Textarea name="description" />
68
+ <Form.Field.RichText name="content" />
69
+
70
+ // Числовые
71
+ <Form.Field.Number name="price" />
72
+ <Form.Field.Slider name="rating" />
73
+ <Form.Field.Currency name="amount" />
74
+
75
+ // Выбор
76
+ <Form.Field.Select name="category" />
77
+ <Form.Field.RadioGroup name="type" />
78
+ <Form.Field.Checkbox name="agree" />
79
+
80
+ // Специальные
81
+ <Form.Field.Date name="birthday" />
82
+ <Form.Field.Phone name="phone" />
83
+ <Form.Field.FileUpload name="avatar" />
84
+ ```
85
+
86
+ [Полный список → docs/fields.md](./docs/fields.md)
87
+
88
+ ### Form-level компоненты
89
+
90
+ ```tsx
91
+ <Form schema={Schema} initialValue={data} onSubmit={save}>
92
+ {/* Условный рендеринг */}
93
+ <Form.When field="type" is="company">
94
+ <Form.Field.String name="companyName" />
95
+ </Form.When>
96
+
97
+ {/* Мультистеп формы */}
98
+ <Form.Steps animated validateOnNext>
99
+ <Form.Steps.Step title="Шаг 1">...</Form.Steps.Step>
100
+ <Form.Steps.Step title="Шаг 2">...</Form.Steps.Step>
101
+ <Form.Steps.Navigation />
102
+ </Form.Steps>
103
+
104
+ {/* Сводка ошибок */}
105
+ <Form.Errors title="Исправьте ошибки:" />
106
+
107
+ {/* JSON-инспектор значений (скрыт в production) */}
108
+ <Form.DebugValues />
109
+
110
+ <Form.Button.Submit />
111
+ </Form>
112
+ ```
113
+
114
+ [Подробнее → docs/form-level.md](./docs/form-level.md)
115
+
116
+ ### Группы и массивы
117
+
118
+ ```tsx
119
+ // Вложенный объект
120
+ <Form.Group name="address">
121
+ <Form.Field.String name="city" /> {/* → address.city */}
122
+ <Form.Field.String name="street" /> {/* → address.street */}
123
+ </Form.Group>
124
+
125
+ // Массив
126
+ <Form.Group.List name="phones">
127
+ <Form.Field.Phone />
128
+ <Form.Group.List.Button.Add>Добавить телефон</Form.Group.List.Button.Add>
129
+ </Form.Group.List>
130
+ ```
131
+
132
+ ### Автоматические constraints из Zod
133
+
134
+ ```tsx
135
+ const Schema = z.object({
136
+ title: z.string().min(2).max(100), // → minLength={2} maxLength={100}
137
+ email: z.string().email(), // → type="email"
138
+ rating: z.number().min(1).max(10), // → min={1} max={10}
139
+ })
140
+
141
+ // DRY: валидация и UI constraints в одном месте
142
+ <Form.Field.String name="title" /> {/* maxLength={100} из схемы */}
143
+ ```
144
+
145
+ ### ZenStack интеграция
146
+
147
+ ```zmodel
148
+ model Product {
149
+ /// @form.title("Название продукта")
150
+ /// @form.placeholder("Введите название")
151
+ title String
152
+
153
+ /// @form.title("Цена")
154
+ /// @form.fieldType("currency")
155
+ /// @form.props({ min: 0, currency: "RUB" })
156
+ price Int
157
+ }
158
+ ```
159
+
160
+ ```tsx
161
+ import { ProductCreateFormSchema } from '@/generated/form-schemas'
162
+ ;<Form.FromSchema schema={ProductCreateFormSchema} initialValue={data} onSubmit={save} />
163
+ ```
164
+
165
+ [Подробнее → docs/zenstack.md](./docs/zenstack.md)
166
+
167
+ ### Offline Support
168
+
169
+ ```tsx
170
+ <Form
171
+ initialValue={data}
172
+ offline={{
173
+ actionType: 'UPDATE_PROFILE',
174
+ onQueued: () => toast.info('Сохранено локально'),
175
+ onSynced: () => toast.success('Синхронизировано'),
176
+ }}
177
+ onSubmit={handleSubmit}
178
+ >
179
+ <Form.OfflineIndicator />
180
+ <Form.Field.String name="name" />
181
+ <Form.Button.Submit />
182
+ </Form>
183
+ ```
184
+
185
+ [Подробнее → docs/offline.md](./docs/offline.md)
186
+
187
+ ---
188
+
189
+ ## Установка
190
+
191
+ ```bash
192
+ # Уже установлен в монорепозитории
193
+ import { Form } from '@lena/form-components'
194
+ ```
195
+
196
+ ### Опциональные зависимости (npm)
197
+
198
+ | Пакет | Для чего |
199
+ | ---------------------- | --------------------------------- |
200
+ | `@dnd-kit/*` | Drag & drop сортировка в массивах |
201
+ | `use-mask-input` | Phone, MaskedInput |
202
+ | `@tiptap/*` | RichText редактор |
203
+ | `@uiw/react-json-view` | Form.DebugValues (JSON инспектор) |
204
+ | `next-intl` | i18n интеграция |
205
+
206
+ ---
207
+
208
+ ## Команды
209
+
210
+ ```bash
211
+ nx build @lena/form-components # Сборка
212
+ nx lint @lena/form-components # Линтинг
213
+ nx test @lena/form-components # Тесты
214
+ ```
215
+
216
+ ---
217
+
218
+ ## Провайдер адресов
219
+
220
+ Поля Address и City поддерживают подключаемые провайдеры геокодинга. DaData (Россия) встроен:
221
+
222
+ ```typescript
223
+ import { createForm, createDaDataProvider } from '@lena/form-components'
224
+
225
+ // Вариант 1: через createForm (рекомендуемый)
226
+ const AppForm = createForm({
227
+ addressProvider: createDaDataProvider({ token: process.env.DADATA_TOKEN }),
228
+ })
229
+
230
+ <AppForm.Field.Address name="address" />
231
+ <AppForm.Field.City name="city" />
232
+
233
+ // Вариант 2: на конкретном поле
234
+ <Form.Field.Address name="address" provider={myProvider} />
235
+
236
+ // Вариант 3: обратная совместимость через token
237
+ <Form.Field.Address name="address" token="dadata-token" />
238
+ ```
239
+
240
+ Для других сервисов — реализуйте интерфейс `AddressProvider`:
241
+
242
+ ```typescript
243
+ const myProvider: AddressProvider = {
244
+ async getSuggestions(query, options) {
245
+ const res = await fetch(`/api/geocode?q=${query}`)
246
+ return res.json() // [{ label, value, data }]
247
+ },
248
+ }
249
+ ```
250
+
251
+ ---
252
+
253
+ ## AI Tooling (MCP)
254
+
255
+ MCP сервер [`@letar/form-mcp`](../form-mcp/README.md) предоставляет AI-ассистентам (Claude Code, Cursor, VS Code Copilot) полный контекст о библиотеке: 40+ полей, паттерны форм, @form.\* директивы.
256
+
257
+ ```json
258
+ { "form-mcp": { "command": "npx", "args": ["-y", "@letar/form-mcp"] } }
259
+ ```
260
+
261
+ ## Bundle Size
262
+
263
+ Библиотека поставляется как ESM с external dependencies. Все тяжёлые зависимости (Chakra, React, Tiptap, dnd-kit) — external и не включаются в bundle.
264
+
265
+ | Модуль | Размер (brotli) | Размер (raw) |
266
+ |--------|----------------|--------------|
267
+ | `@letar/forms` (все 40 полей) | **20 KB** | 109 KB |
268
+ | `@letar/forms/fields/text` | < 1 KB | re-export |
269
+ | `@letar/forms/fields/number` | < 1 KB | re-export |
270
+ | `@letar/forms/fields/datetime` | < 1 KB | re-export |
271
+ | `@letar/forms/fields/selection` | < 1 KB | re-export |
272
+ | `@letar/forms/fields/boolean` | < 1 KB | re-export |
273
+ | `@letar/forms/fields/specialized` | < 1 KB | re-export |
274
+ | `@letar/forms/offline` | < 1 KB | 5 KB |
275
+ | `@letar/forms/i18n` | < 1 KB | 13 KB |
276
+
277
+ Категорийные entry points (`fields/*`) позволяют импортировать только нужные поля:
278
+
279
+ ```typescript
280
+ // Полный импорт — все 40 полей
281
+ import { Form } from '@letar/forms'
282
+
283
+ // Категорийный импорт — только текстовые поля
284
+ import { FieldString, FieldTextarea } from '@letar/forms/fields/text'
285
+ ```
286
+
287
+ Метрики проверяются в CI через [size-limit](https://github.com/ai/size-limit).
288
+
289
+ ### Ре-рендеры
290
+
291
+ При вводе текста в одно поле формы из 10 полей — **остальные 9 полей НЕ ре-рендерятся** (0 лишних рендеров). TanStack Form обеспечивает field-level подписки — каждое поле изолировано.
292
+
293
+ ## Связанные документы
294
+
295
+ - [/.claude/docs/forms.md](../../.claude/docs/forms.md) — документация по формам
296
+ - [/.claude/docs/pwa-offline.md](../../.claude/docs/pwa-offline.md) — оффлайн-формы
297
+ - [/libs/form-mcp](../form-mcp/) — MCP сервер для AI-ассистентов
298
+ - [PLAN.md](./PLAN.md) — план развития библиотеки
299
+ - [TESTING_PLAN.md](./TESTING_PLAN.md) — план тестирования
300
+
301
+ ---
302
+
303
+ **Версия:** 0.59.0
304
+ **Последнее обновление:** 2026-04-01
@@ -0,0 +1,78 @@
1
+ import { createField, FieldTooltip, FieldError } from './chunk-HWVOFWAT.js';
2
+ import { Field, Checkbox, HStack, Switch } from '@chakra-ui/react';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ var FieldCheckbox = createField({
6
+ displayName: "FieldCheckbox",
7
+ render: ({ field, fullPath, resolved, hasError, errorMessage, componentProps }) => /* @__PURE__ */ jsxs(
8
+ Field.Root,
9
+ {
10
+ invalid: hasError,
11
+ required: resolved.required,
12
+ disabled: resolved.disabled,
13
+ readOnly: resolved.readOnly,
14
+ children: [
15
+ /* @__PURE__ */ jsxs(
16
+ Checkbox.Root,
17
+ {
18
+ checked: !!field.state.value,
19
+ onCheckedChange: (e) => field.handleChange(!!e.checked),
20
+ colorPalette: componentProps.colorPalette ?? "brand",
21
+ size: componentProps.size ?? "md",
22
+ disabled: resolved.disabled,
23
+ readOnly: resolved.readOnly,
24
+ "data-field-name": fullPath,
25
+ children: [
26
+ /* @__PURE__ */ jsx(Checkbox.HiddenInput, { onBlur: field.handleBlur }),
27
+ /* @__PURE__ */ jsx(Checkbox.Control, {}),
28
+ resolved.label && /* @__PURE__ */ jsx(Checkbox.Label, { children: resolved.tooltip ? /* @__PURE__ */ jsxs(HStack, { gap: 1, children: [
29
+ /* @__PURE__ */ jsx("span", { children: resolved.label }),
30
+ /* @__PURE__ */ jsx(FieldTooltip, { ...resolved.tooltip })
31
+ ] }) : resolved.label })
32
+ ]
33
+ }
34
+ ),
35
+ /* @__PURE__ */ jsx(FieldError, { hasError, errorMessage, helperText: resolved.helperText })
36
+ ]
37
+ }
38
+ )
39
+ });
40
+ var FieldSwitch = createField({
41
+ displayName: "FieldSwitch",
42
+ render: ({ field, fullPath, resolved, hasError, errorMessage, componentProps }) => /* @__PURE__ */ jsxs(
43
+ Field.Root,
44
+ {
45
+ invalid: hasError,
46
+ required: resolved.required,
47
+ disabled: resolved.disabled,
48
+ readOnly: resolved.readOnly,
49
+ children: [
50
+ /* @__PURE__ */ jsxs(
51
+ Switch.Root,
52
+ {
53
+ checked: !!field.state.value,
54
+ onCheckedChange: (e) => field.handleChange(e.checked),
55
+ colorPalette: componentProps.colorPalette ?? "brand",
56
+ size: componentProps.size ?? "md",
57
+ disabled: resolved.disabled,
58
+ readOnly: resolved.readOnly,
59
+ "data-field-name": fullPath,
60
+ children: [
61
+ /* @__PURE__ */ jsx(Switch.HiddenInput, { onBlur: field.handleBlur }),
62
+ /* @__PURE__ */ jsx(Switch.Control, { children: /* @__PURE__ */ jsx(Switch.Thumb, {}) }),
63
+ resolved.label && /* @__PURE__ */ jsx(Switch.Label, { children: resolved.tooltip ? /* @__PURE__ */ jsxs(HStack, { gap: 1, children: [
64
+ /* @__PURE__ */ jsx("span", { children: resolved.label }),
65
+ /* @__PURE__ */ jsx(FieldTooltip, { ...resolved.tooltip })
66
+ ] }) : resolved.label })
67
+ ]
68
+ }
69
+ ),
70
+ /* @__PURE__ */ jsx(FieldError, { hasError, errorMessage, helperText: resolved.helperText })
71
+ ]
72
+ }
73
+ )
74
+ });
75
+
76
+ export { FieldCheckbox, FieldSwitch };
77
+ //# sourceMappingURL=chunk-6QOPSQ3Z.js.map
78
+ //# sourceMappingURL=chunk-6QOPSQ3Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/declarative/form-fields/boolean/field-checkbox.tsx","../src/lib/declarative/form-fields/boolean/field-switch.tsx"],"names":["jsxs","Field","jsx","HStack"],"mappings":"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","file":"chunk-6QOPSQ3Z.js","sourcesContent":["'use client'\n\nimport { Checkbox, Field, HStack } from '@chakra-ui/react'\nimport type { ReactElement } from 'react'\nimport type { CheckboxFieldProps } from '../../types'\nimport { createField, FieldError } from '../base'\nimport { FieldTooltip } from '../base/field-tooltip'\n\n/**\n * Form.Field.Checkbox - Boolean checkbox field\n *\n * Renders a Chakra Checkbox with automatic form integration and error display.\n *\n * @example\n * ```tsx\n * <Form.Field.Checkbox name=\"active\" label=\"Active\" />\n * ```\n *\n * @example With color palette\n * ```tsx\n * <Form.Field.Checkbox name=\"terms\" label=\"Accept terms\" colorPalette=\"green\" />\n * ```\n */\nexport const FieldCheckbox = createField<CheckboxFieldProps, boolean>({\n displayName: 'FieldCheckbox',\n render: ({ field, fullPath, resolved, hasError, errorMessage, componentProps }): ReactElement => (\n <Field.Root\n invalid={hasError}\n required={resolved.required}\n disabled={resolved.disabled}\n readOnly={resolved.readOnly}\n >\n <Checkbox.Root\n checked={!!field.state.value}\n onCheckedChange={(e) => field.handleChange(!!e.checked)}\n colorPalette={componentProps.colorPalette ?? 'brand'}\n size={componentProps.size ?? 'md'}\n disabled={resolved.disabled}\n readOnly={resolved.readOnly}\n data-field-name={fullPath}\n >\n <Checkbox.HiddenInput onBlur={field.handleBlur} />\n <Checkbox.Control />\n {resolved.label && (\n <Checkbox.Label>\n {resolved.tooltip ? (\n <HStack gap={1}>\n <span>{resolved.label}</span>\n <FieldTooltip {...resolved.tooltip} />\n </HStack>\n ) : (\n resolved.label\n )}\n </Checkbox.Label>\n )}\n </Checkbox.Root>\n <FieldError hasError={hasError} errorMessage={errorMessage} helperText={resolved.helperText} />\n </Field.Root>\n ),\n})\n","'use client'\n\nimport { Field, HStack, Switch } from '@chakra-ui/react'\nimport type { ReactElement } from 'react'\nimport type { SwitchFieldProps } from '../../types'\nimport { createField, FieldError } from '../base'\nimport { FieldTooltip } from '../base/field-tooltip'\n\n/**\n * Form.Field.Switch - Boolean switch/toggle field\n *\n * Renders a Chakra Switch with automatic form integration and error display.\n *\n * @example\n * ```tsx\n * <Form.Field.Switch name=\"notifications\" label=\"Enable notifications\" />\n * ```\n *\n * @example With color palette and size\n * ```tsx\n * <Form.Field.Switch name=\"darkMode\" label=\"Dark mode\" colorPalette=\"purple\" size=\"lg\" />\n * ```\n */\nexport const FieldSwitch = createField<SwitchFieldProps, boolean>({\n displayName: 'FieldSwitch',\n render: ({ field, fullPath, resolved, hasError, errorMessage, componentProps }): ReactElement => (\n <Field.Root\n invalid={hasError}\n required={resolved.required}\n disabled={resolved.disabled}\n readOnly={resolved.readOnly}\n >\n <Switch.Root\n checked={!!field.state.value}\n onCheckedChange={(e) => field.handleChange(e.checked)}\n colorPalette={componentProps.colorPalette ?? 'brand'}\n size={componentProps.size ?? 'md'}\n disabled={resolved.disabled}\n readOnly={resolved.readOnly}\n data-field-name={fullPath}\n >\n <Switch.HiddenInput onBlur={field.handleBlur} />\n <Switch.Control>\n <Switch.Thumb />\n </Switch.Control>\n {resolved.label && (\n <Switch.Label>\n {resolved.tooltip ? (\n <HStack gap={1}>\n <span>{resolved.label}</span>\n <FieldTooltip {...resolved.tooltip} />\n </HStack>\n ) : (\n resolved.label\n )}\n </Switch.Label>\n )}\n </Switch.Root>\n <FieldError hasError={hasError} errorMessage={errorMessage} helperText={resolved.helperText} />\n </Field.Root>\n ),\n})\n"]}