@letar/forms 1.0.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 +83 -0
- package/LICENSE +21 -0
- package/README.md +188 -0
- package/chunk-G3HYXHCZ.js +435 -0
- package/chunk-G3HYXHCZ.js.map +1 -0
- package/chunk-GIBNEYK3.js +191 -0
- package/chunk-GIBNEYK3.js.map +1 -0
- package/i18n.js +3 -0
- package/i18n.js.map +1 -0
- package/index.js +7842 -0
- package/index.js.map +1 -0
- package/offline.js +3 -0
- package/offline.js.map +1 -0
- package/package.json +96 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Все значимые изменения в библиотеке @lena/form-components документируются в этом файле.
|
|
4
|
+
|
|
5
|
+
Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.0.0/).
|
|
6
|
+
|
|
7
|
+
## [0.54.1] - 2026-01-05
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `FieldNumber`: для опциональных полей не передаём min/max в NumberInput когда значение пустое — убрана красная рамка для пустых опциональных полей
|
|
12
|
+
|
|
13
|
+
## [0.54.0] - 2026-01-03
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `form-from-schema.spec.tsx` — unit тесты для `FormFromSchema` (~15 тестов)
|
|
18
|
+
- `form-with-api.spec.tsx` — unit тесты для `FormWithApi` (~12 тестов)
|
|
19
|
+
- Покрытие тестами всех критичных компонентов схемогенерации
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Deprecated type aliases централизованы в `form-fields/index.ts`
|
|
24
|
+
- Удалены локальные deprecated экспорты из 7 selection компонентов
|
|
25
|
+
- `field-select.tsx` использует `BaseOption<string | number>[]` вместо `SelectOption`
|
|
26
|
+
|
|
27
|
+
### Improved
|
|
28
|
+
|
|
29
|
+
- Общее покрытие тестами: +27 unit тестов
|
|
30
|
+
- Обратная совместимость сохранена через централизованный реэкспорт deprecated типов
|
|
31
|
+
|
|
32
|
+
## [0.53.0] - 2025-12-31
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- Оптимизация производительности форм
|
|
37
|
+
- Улучшенная мемоизация в form-fields
|
|
38
|
+
|
|
39
|
+
## [0.51.0] - 2025-12-24
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- `useAsyncSearch` — общий хук для async поиска с debounce (Combobox, Autocomplete)
|
|
44
|
+
- `AsyncQueryFn`, `AsyncQueryResult` — типы для async запросов
|
|
45
|
+
- Persistence TTL — опция `ttl` для времени жизни черновика
|
|
46
|
+
- `ClearDraftButton` — компонент кнопки очистки черновика
|
|
47
|
+
- `savedAt` — timestamp сохранения черновика в `FormPersistenceResult`
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- `FieldCombobox` и `FieldAutocomplete` используют `useAsyncSearch` вместо дублирования логики
|
|
52
|
+
- `useFormPersistence` теперь сохраняет данные в новом формате с метаданными (version, savedAt)
|
|
53
|
+
- Обратная совместимость со старым форматом сохранённых данных
|
|
54
|
+
|
|
55
|
+
## [0.50.0] - 2025-12-24
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- `SelectionFieldLabel` — общий компонент для label+tooltip в selection полях
|
|
60
|
+
- `useGroupedOptions` — хук группировки опций (Combobox, Listbox, Select)
|
|
61
|
+
- `getOptionLabel` — утилита для получения label опции
|
|
62
|
+
- `zod-utils.ts` — централизованные функции `unwrapSchema`, `unwrapSchemaWithRequired`
|
|
63
|
+
- `LinkPopover` — модальное окно для ввода URL вместо `window.prompt()`
|
|
64
|
+
- Защита от циклических схем в `schema-traversal` (WeakSet + MAX_DEPTH=20)
|
|
65
|
+
- `SWITCH_STYLES` константы в `field-schedule.tsx`
|
|
66
|
+
|
|
67
|
+
### Changed
|
|
68
|
+
|
|
69
|
+
- `extractConstraints` рефакторинг с generic handler pattern
|
|
70
|
+
- `FormSteps` декомпозиция на хуки: `useStepState`, `useStepPersistence`, `useStepNavigation`
|
|
71
|
+
- Selection поля используют общие компоненты вместо дублирования
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
|
|
75
|
+
- `field-rich-text`: добавлен try/catch для JSON.parse
|
|
76
|
+
|
|
77
|
+
### Removed
|
|
78
|
+
|
|
79
|
+
- ~500 строк дублирующегося кода
|
|
80
|
+
|
|
81
|
+
## [0.49.0] и ранее
|
|
82
|
+
|
|
83
|
+
История изменений до v0.50.0 не документировалась.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Letar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# @letar/forms
|
|
2
|
+
|
|
3
|
+
Declarative form components for React with **40+ field types**, powered by [TanStack Form](https://tanstack.com/form) and [Chakra UI v3](https://chakra-ui.com).
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@letar/forms)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @letar/forms @tanstack/react-form @chakra-ui/react zod
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { Form } from '@letar/forms'
|
|
16
|
+
import { z } from 'zod/v4'
|
|
17
|
+
|
|
18
|
+
const Schema = z.object({
|
|
19
|
+
title: z.string().min(2).meta({ ui: { title: 'Title', placeholder: 'Enter...' } }),
|
|
20
|
+
rating: z.number().min(0).max(10).meta({ ui: { title: 'Rating' } }),
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
function MyForm() {
|
|
24
|
+
return (
|
|
25
|
+
<Form schema={Schema} initialValue={{ title: '', rating: 5 }} onSubmit={save}>
|
|
26
|
+
<Form.Field.String name="title" />
|
|
27
|
+
<Form.Field.Number name="rating" />
|
|
28
|
+
<Form.Button.Submit>Save</Form.Button.Submit>
|
|
29
|
+
</Form>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Or fully auto-generated from schema:**
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
<Form.FromSchema schema={Schema} initialValue={data} onSubmit={handleSubmit} submitLabel="Create" />
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Philosophy: Separate Layout from Logic
|
|
41
|
+
|
|
42
|
+
| Aspect | Where defined | How used in JSX |
|
|
43
|
+
| --------------- | -------------------------- | ------------------------------- |
|
|
44
|
+
| **Validation** | Zod schema | `schema={Schema}` |
|
|
45
|
+
| **UI metadata** | Zod `.meta({ ui: {...} })` | Auto-extracted from schema |
|
|
46
|
+
| **Structure** | TypeScript types | `initialValue={data}` |
|
|
47
|
+
| **Layout** | JSX | `<HStack>`, `<VStack>`, `<Box>` |
|
|
48
|
+
|
|
49
|
+
**Result:** JSX contains only layout and field names. All logic lives in the schema.
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
### 40+ Field Components
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
// Text
|
|
57
|
+
<Form.Field.String name="title" />
|
|
58
|
+
<Form.Field.Textarea name="description" />
|
|
59
|
+
<Form.Field.RichText name="content" />
|
|
60
|
+
<Form.Field.Password name="password" />
|
|
61
|
+
|
|
62
|
+
// Numbers
|
|
63
|
+
<Form.Field.Number name="price" />
|
|
64
|
+
<Form.Field.Slider name="rating" />
|
|
65
|
+
<Form.Field.Currency name="amount" />
|
|
66
|
+
|
|
67
|
+
// Selection
|
|
68
|
+
<Form.Field.Select name="category" />
|
|
69
|
+
<Form.Field.Combobox name="search" />
|
|
70
|
+
<Form.Field.RadioGroup name="type" />
|
|
71
|
+
<Form.Field.Checkbox name="agree" />
|
|
72
|
+
|
|
73
|
+
// Date & Time
|
|
74
|
+
<Form.Field.Date name="birthday" />
|
|
75
|
+
<Form.Field.DateRange name="period" />
|
|
76
|
+
<Form.Field.Time name="time" />
|
|
77
|
+
|
|
78
|
+
// Specialized
|
|
79
|
+
<Form.Field.Phone name="phone" />
|
|
80
|
+
<Form.Field.FileUpload name="avatar" />
|
|
81
|
+
<Form.Field.ColorPicker name="color" />
|
|
82
|
+
<Form.Field.PinInput name="code" />
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Conditional Rendering
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
<Form schema={Schema} initialValue={data} onSubmit={save}>
|
|
89
|
+
<Form.Field.Select name="type" />
|
|
90
|
+
|
|
91
|
+
<Form.When field="type" is="company">
|
|
92
|
+
<Form.Field.String name="companyName" />
|
|
93
|
+
</Form.When>
|
|
94
|
+
|
|
95
|
+
<Form.Button.Submit />
|
|
96
|
+
</Form>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Multi-Step Forms
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
<Form schema={Schema} initialValue={data} onSubmit={save}>
|
|
103
|
+
<Form.Steps animated validateOnNext>
|
|
104
|
+
<Form.Steps.Step title="Personal Info">
|
|
105
|
+
<Form.Field.String name="name" />
|
|
106
|
+
<Form.Field.String name="email" />
|
|
107
|
+
</Form.Steps.Step>
|
|
108
|
+
|
|
109
|
+
<Form.Steps.Step title="Address">
|
|
110
|
+
<Form.Field.String name="city" />
|
|
111
|
+
<Form.Field.String name="street" />
|
|
112
|
+
</Form.Steps.Step>
|
|
113
|
+
|
|
114
|
+
<Form.Steps.Navigation />
|
|
115
|
+
</Form.Steps>
|
|
116
|
+
</Form>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Groups and Arrays
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
// Nested object
|
|
123
|
+
<Form.Group name="address">
|
|
124
|
+
<Form.Field.String name="city" /> {/* → address.city */}
|
|
125
|
+
<Form.Field.String name="street" /> {/* → address.street */}
|
|
126
|
+
</Form.Group>
|
|
127
|
+
|
|
128
|
+
// Array of items
|
|
129
|
+
<Form.Group.List name="phones">
|
|
130
|
+
<Form.Field.Phone />
|
|
131
|
+
<Form.Group.List.Button.Add>Add Phone</Form.Group.List.Button.Add>
|
|
132
|
+
</Form.Group.List>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Auto Constraints from Zod
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
const Schema = z.object({
|
|
139
|
+
title: z.string().min(2).max(100), // → minLength={2} maxLength={100}
|
|
140
|
+
email: z.string().email(), // → type="email"
|
|
141
|
+
rating: z.number().min(1).max(10), // → min={1} max={10}
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
// DRY: validation and UI constraints in one place
|
|
145
|
+
<Form.Field.String name="title" /> {/* maxLength={100} from schema */}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Error Summary
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
<Form schema={Schema} initialValue={data} onSubmit={save}>
|
|
152
|
+
<Form.Field.String name="name" />
|
|
153
|
+
<Form.Field.String name="email" />
|
|
154
|
+
|
|
155
|
+
<Form.Errors title="Please fix:" />
|
|
156
|
+
<Form.Button.Submit />
|
|
157
|
+
</Form>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Subpath Exports
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
// Offline support (PWA)
|
|
164
|
+
import { FormOfflineIndicator, useOfflineForm } from '@letar/forms/offline'
|
|
165
|
+
|
|
166
|
+
// Internationalization
|
|
167
|
+
import { FormI18nProvider, useFormI18n } from '@letar/forms/i18n'
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Peer Dependencies
|
|
171
|
+
|
|
172
|
+
| Package | Version | Required |
|
|
173
|
+
| ---------------------- | --------- | -------- |
|
|
174
|
+
| `react` | >= 18.0.0 | Yes |
|
|
175
|
+
| `@tanstack/react-form` | >= 1.0.0 | Yes |
|
|
176
|
+
| `@chakra-ui/react` | >= 3.0.0 | Yes |
|
|
177
|
+
| `framer-motion` | >= 10.0.0 | Yes |
|
|
178
|
+
| `zod` | >= 3.24.0 | Yes |
|
|
179
|
+
| `@dnd-kit/*` | >= 6.0.0 | Optional |
|
|
180
|
+
| `use-mask-input` | >= 3.0.0 | Optional |
|
|
181
|
+
|
|
182
|
+
## Documentation
|
|
183
|
+
|
|
184
|
+
Full documentation and live examples: **[forms.letar.best](https://forms.letar.best)**
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
[MIT](./LICENSE)
|