@companix/formkit 0.0.29 → 0.0.31
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/README.md +342 -36
- package/dist/ConditionBranch.d.ts +7 -0
- package/dist/bundle.es.js +310 -262
- package/dist/core/builders/syntax.d.ts +6 -3
- package/dist/core/extract.d.ts +4 -1
- package/dist/core/types.d.ts +2 -1
- package/dist/manager/read-scheme.d.ts +4 -1
- package/package.json +1 -1
- package/dist/Condition.d.ts +0 -7
package/README.md
CHANGED
|
@@ -1,58 +1,364 @@
|
|
|
1
|
-
|
|
1
|
+
# @companix/formkit
|
|
2
|
+
|
|
3
|
+
Формы на React одной декларативной схемой. Поля, раскладка, условия и проверка описываются деревом из обычных вызовов
|
|
4
|
+
функций, а значения формы TypeScript выводит из самой схемы — без ручных интерфейсов, `useState` на каждое поле и
|
|
5
|
+
`register` в разметке.
|
|
2
6
|
|
|
3
7
|
```tsx
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const scheme = [
|
|
9
|
+
Label('Имя')(TextForm('name', { placeholder: 'Иван', $rules: { required: true } })),
|
|
10
|
+
CheckboxForm('hasCompany', { title: 'Представляю компанию' }),
|
|
11
|
+
OptionalCondition('hasCompany', { canActivate: (checked: boolean) => checked })(
|
|
12
|
+
Context('company')(Label('Компания')(TextForm('name', { placeholder: 'ООО «Ромашка»' })))
|
|
13
|
+
)
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
// onSubmit получит { name: string; hasCompany: boolean; company?: { name: string } }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`TextForm`, `CheckboxForm` и `Label` здесь — свои поле и раскладка проекта: как их завести, показано ниже.
|
|
20
|
+
|
|
21
|
+
## Почему formkit
|
|
22
|
+
|
|
23
|
+
- **Форма — данные, а не разметка.** Схема — массив, который собирают функциями: общий блок полей пишется один раз и
|
|
24
|
+
вставляется в любую форму, вариант формы — другой набор элементов, а не ветвление в JSX.
|
|
25
|
+
- **Типы из схемы.** `onSubmit`, `onChange`, `defaultValues`, `setValue` и `useValue` знают имена и типы полей,
|
|
26
|
+
вложенные контексты и необязательность полей под условием.
|
|
27
|
+
- **Поле пишется один раз.** `createForm` превращает любой компонент ввода в поле: умолчание, «что считать пустым» и
|
|
28
|
+
отрисовка ошибки живут в нём, а не в каждой форме.
|
|
29
|
+
- **Условия и вложенность из коробки.** `OptionalCondition` показывает поля по значению другого поля, `Context`
|
|
30
|
+
складывает их в объект; скрытое поле не попадает ни в значения, ни в проверку, а под `NullableCondition` приходит
|
|
31
|
+
`null`.
|
|
32
|
+
- **Состояние вне React.** Значения держит менеджер формы: правка поля перерисовывает это поле и тех, кто на него
|
|
33
|
+
подписан, а не всю форму и не экран вокруг неё.
|
|
34
|
+
- **Изменённость.** Форма знает, что её правили, сообщает об этом и при отправке без изменений вызывает `onEqual`
|
|
35
|
+
вместо запроса.
|
|
36
|
+
|
|
37
|
+
## Установка
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
npm i @companix/formkit
|
|
10
41
|
```
|
|
11
42
|
|
|
12
|
-
|
|
43
|
+
Нужен React 18.
|
|
44
|
+
|
|
45
|
+
## Форма за минуту
|
|
13
46
|
|
|
14
47
|
```tsx
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
48
|
+
import { useMemo } from 'react'
|
|
49
|
+
import { createForm, createLayout, useForm, FormLayout } from '@companix/formkit'
|
|
50
|
+
|
|
51
|
+
// поле: умолчание, проверка обязательности и компонент
|
|
52
|
+
const TextForm = createForm<string, { placeholder: string }>({
|
|
53
|
+
defaultValue: '',
|
|
54
|
+
getRequireCheck: () => (value) => {
|
|
55
|
+
if (value.trim() === '') {
|
|
56
|
+
throw ''
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
getForm: ({ placeholder }) => {
|
|
60
|
+
return ({ field, error, disabled }) => {
|
|
61
|
+
return (
|
|
62
|
+
<div className="field">
|
|
63
|
+
<input
|
|
64
|
+
ref={field.ref}
|
|
65
|
+
value={field.value}
|
|
66
|
+
placeholder={placeholder}
|
|
67
|
+
disabled={disabled}
|
|
68
|
+
onChange={(e) => field.onChange(e.target.value)}
|
|
69
|
+
/>
|
|
70
|
+
{error?.messages?.map((message) => (
|
|
71
|
+
<p key={message}>{message}</p>
|
|
72
|
+
))}
|
|
73
|
+
</div>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
18
76
|
}
|
|
19
77
|
})
|
|
20
78
|
|
|
21
|
-
|
|
79
|
+
// раскладка: подпись над полем
|
|
80
|
+
const Label = createLayout((text: string) => {
|
|
22
81
|
return ({ children }) => {
|
|
23
|
-
return
|
|
82
|
+
return (
|
|
83
|
+
<label className="label">
|
|
84
|
+
<span>{text}</span>
|
|
85
|
+
{children}
|
|
86
|
+
</label>
|
|
87
|
+
)
|
|
24
88
|
}
|
|
25
89
|
})
|
|
26
90
|
|
|
27
|
-
export const
|
|
28
|
-
|
|
29
|
-
return
|
|
91
|
+
export const ProfileForm = () => {
|
|
92
|
+
const scheme = useMemo(() => {
|
|
93
|
+
return [
|
|
94
|
+
Label('Имя')(TextForm('name', { placeholder: 'Иван', $rules: { required: true } })),
|
|
95
|
+
Label('Город')(TextForm('city', { placeholder: 'Москва' }))
|
|
96
|
+
]
|
|
97
|
+
}, [])
|
|
98
|
+
|
|
99
|
+
const form = useForm(scheme, {
|
|
100
|
+
defaultValues: { city: 'Москва' },
|
|
101
|
+
onSubmit: async (values) => {
|
|
102
|
+
await api.saveProfile(values) // values: { name: string; city: string }
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<>
|
|
108
|
+
<FormLayout manager={form.manager} />
|
|
109
|
+
<button onClick={form.handleSubmit}>Сохранить</button>
|
|
110
|
+
</>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Менеджер формы создаётся один раз: схему и `defaultValues` `useForm` читает при первом рендере, поэтому схему держат в
|
|
116
|
+
`useMemo`. `FormLayout` рисует схему и может стоять где угодно — в окне, на странице, в шаге мастера.
|
|
117
|
+
|
|
118
|
+
## Поле — `createForm`
|
|
119
|
+
|
|
120
|
+
Поле — это компонент ввода плюс три ответа: какое у него значение по умолчанию, что для него значит «пусто» и как его
|
|
121
|
+
нарисовать по параметрам из схемы.
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
const SelectForm = <T,>(defaultValue: T | null) => {
|
|
125
|
+
return createForm<T | null, { options: { value: T; title: string }[] }>({
|
|
126
|
+
defaultValue,
|
|
127
|
+
getRequireCheck: () => (value) => {
|
|
128
|
+
if (value === null) {
|
|
129
|
+
throw ''
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
getForm: ({ options }) => {
|
|
133
|
+
return ({ field, error }) => (
|
|
134
|
+
<Select options={options} value={field.value} onChange={field.onChange} error={error} />
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
SelectForm<'day' | 'night'>('day')('mode', { options: MODES })
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Компонент получает `field` (`value`, `onChange`, `ref` для фокуса на ошибке), `error` и `disabled` формы. Умолчание,
|
|
144
|
+
которое зависит от места, задают фабрикой, как у `SelectForm` выше: `NumberInputForm(1)('count', …)`.
|
|
145
|
+
|
|
146
|
+
## Раскладка — `createLayout`
|
|
147
|
+
|
|
148
|
+
Раскладка оборачивает поля разметкой. Параметр раскладки — один аргумент; раскладку без параметров вызывают сразу.
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
const Card = createLayout(({ title, hint }: { title: string; hint?: string }) => {
|
|
152
|
+
return ({ children }) => (
|
|
153
|
+
<section className="card">
|
|
154
|
+
<h3>{title}</h3>
|
|
155
|
+
{hint && <p>{hint}</p>}
|
|
156
|
+
{children}
|
|
157
|
+
</section>
|
|
158
|
+
)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
const Double = createLayout(() => {
|
|
162
|
+
return ({ children }) => <div className="double">{children}</div>
|
|
163
|
+
})()
|
|
164
|
+
|
|
165
|
+
Card({ title: 'Контакты', hint: 'Видят только менеджеры' })(
|
|
166
|
+
Double(TextForm('phone', { placeholder: '+7' }), TextForm('email', { placeholder: 'mail@site.ru' }))
|
|
167
|
+
)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Схема
|
|
171
|
+
|
|
172
|
+
| Элемент | Что делает | В значениях |
|
|
173
|
+
| ------------------------------------------------ | ------------------------------------------------------------------------- | ------------------ |
|
|
174
|
+
| `XForm('name', params)` | поле | `name: V` |
|
|
175
|
+
| `Layout(params)(…)` | разметка вокруг полей | поля как есть |
|
|
176
|
+
| `Context('name')(…)` | вложенный объект: имена полей внутри — `name.field` | `name: { … }` |
|
|
177
|
+
| `OptionalCondition('field', { canActivate })(…)` | поля показаны, пока `canActivate(значение поля)` верно; имя — полный путь | поля необязательны |
|
|
178
|
+
| `NullableCondition('field', { canActivate })(…)` | как `OptionalCondition`, но скрытая ветка отдаёт `null` своим именам | `name: V \| null` |
|
|
179
|
+
| `Visablility({ hidden })(…)` | поля не рисуются, но несут значение из `defaultValues` | поля необязательны |
|
|
180
|
+
| `createExtraForm(…)` | поля, которые пользователь добавляет и убирает сам | поля необязательны |
|
|
181
|
+
|
|
182
|
+
Значения `onSubmit` и `onChange` выводятся из схемы сами, тип `defaultValues` схемы — `GetDefaultValues<typeof scheme>`.
|
|
183
|
+
|
|
184
|
+
## Проверка
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
TextForm('inn', {
|
|
188
|
+
placeholder: '12 цифр',
|
|
189
|
+
$rules: {
|
|
190
|
+
required: true,
|
|
191
|
+
validate: (value) => {
|
|
192
|
+
if (!/^\d{12}$/.test(value)) {
|
|
193
|
+
throw 'ИНН — 12 цифр'
|
|
194
|
+
}
|
|
195
|
+
}
|
|
30
196
|
}
|
|
31
197
|
})
|
|
32
198
|
```
|
|
33
199
|
|
|
34
|
-
|
|
200
|
+
- `required` проверяет поле его же `getRequireCheck`; `validate` — после него. Без `required` `validate` работает,
|
|
201
|
+
только если поле не пустое.
|
|
202
|
+
- Проверка бросает строку: `throw ''` подсвечивает поле, `throw 'текст'` — с сообщением, массив строк — несколько
|
|
203
|
+
сообщений. Ошибку рисует компонент поля из `error.messages`.
|
|
204
|
+
- `handleSubmit` проверяет поля, которые форма показывает, и ставит фокус на первое ошибочное. Поле скрытого условия
|
|
205
|
+
отправку не держит. После первой попытки поля проверяются на каждой правке.
|
|
206
|
+
- Ошибку от сервера ставит `setError` из второго аргумента `onSubmit`: `setError('inn', { message: 'ИНН занят' })`.
|
|
207
|
+
|
|
208
|
+
## Значения, умолчания и условия
|
|
209
|
+
|
|
210
|
+
У поля два источника начального значения: умолчание компонента (`defaultValue` из `createForm`) и `defaultValues`
|
|
211
|
+
формы. Стартовое значение — `defaultValues`, а без них — умолчание компонента. От стартового значения считается
|
|
212
|
+
изменённость, и с него поле начинает:
|
|
213
|
+
|
|
214
|
+
- при первом показе;
|
|
215
|
+
- когда условие снова показывает поле: скрытое поле теряет значение и ошибку, вернувшееся — начинает заново со
|
|
216
|
+
стартового, а не с того, что ввели до скрытия.
|
|
217
|
+
|
|
218
|
+
Значения формы — `onChange`, `getValues()` и отправка — это то, что форма показывает. Поля скрытых условий в них не
|
|
219
|
+
входят, а поле, которое изменение только что открыло, входит сразу, ещё до монтирования, со стартовым значением.
|
|
220
|
+
|
|
221
|
+
Отсюда простое правило: `defaultValues` — только данные. Где данных нет, передавайте `undefined`, и поле возьмёт своё
|
|
222
|
+
умолчание; повторять умолчание поля в `defaultValues` не нужно.
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
defaultValues: {
|
|
226
|
+
hasEscorts: escorts !== null,
|
|
227
|
+
escorts: escorts ?? undefined // нет данных — поля начнут со своих умолчаний
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Данные или `null` — `NullableCondition`
|
|
35
232
|
|
|
36
|
-
|
|
233
|
+
Часто включаемый блок в данных — объект или `null`: выключенное условие хранится как `null`, а не отдельным флажком.
|
|
234
|
+
`OptionalCondition` даёт такому блоку `undefined` — скрытая ветка пропадает из значений. `NullableCondition` ведёт себя
|
|
235
|
+
так же, но скрытая ветка отдаёт `null` своим именам — полям и контекстам уровня ветки; раскладки и вложенные условия
|
|
236
|
+
внутри неё прозрачны. Имена — как `.optional()` и `.nullable()` в zod: `name?: V` против `name: V | null`.
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
37
239
|
const scheme = [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
options: []
|
|
42
|
-
})
|
|
43
|
-
),
|
|
44
|
-
Splitter(),
|
|
45
|
-
Double()(
|
|
46
|
-
Label('Фамилия')(
|
|
47
|
-
InputForm('surname', {
|
|
48
|
-
placeholder: 'Введите фамилию'
|
|
49
|
-
})
|
|
50
|
-
),
|
|
51
|
-
Label('Отчество')(
|
|
52
|
-
InputForm('patronymic', {
|
|
53
|
-
placeholder: 'Введите отчество'
|
|
54
|
-
})
|
|
55
|
-
)
|
|
240
|
+
CheckboxForm('hasCompany', { title: 'Представляю компанию' }),
|
|
241
|
+
NullableCondition('hasCompany', { canActivate: (checked: boolean) => checked })(
|
|
242
|
+
Context('company')(Label('Компания')(TextForm('name', { placeholder: 'ООО «Ромашка»' })))
|
|
56
243
|
)
|
|
57
244
|
]
|
|
245
|
+
|
|
246
|
+
// onSubmit получит { hasCompany: boolean; company: { name: string } | null }
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
`null` у такого имени в `defaultValues` — отсутствие данных, как `undefined`: поля ветки начнут с умолчаний своих
|
|
250
|
+
компонентов. Блок из данных передаётся как есть, флажок выводится из него:
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
const form = useForm(scheme, {
|
|
254
|
+
defaultValues: {
|
|
255
|
+
hasCompany: profile.company !== null,
|
|
256
|
+
company: profile.company // { name: string } | null
|
|
257
|
+
},
|
|
258
|
+
onSubmit: async (values) => {
|
|
259
|
+
await api.saveProfile(values) // company — как в данных: объект или null
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Ветка из одного поля, у которого `null` — своё значение (стёртое число, дата без выбора), отдаёт `null` и скрытой, и
|
|
265
|
+
пустой: различает их флажок.
|
|
266
|
+
|
|
267
|
+
## Живая форма и изменённость
|
|
268
|
+
|
|
269
|
+
```tsx
|
|
270
|
+
const form = useForm(scheme, {
|
|
271
|
+
defaultValues,
|
|
272
|
+
// значения после каждой правки — расчёт и подсказки поверх полей, без кнопки отправки
|
|
273
|
+
onChange: (values) => setDraft(toDraft(values)),
|
|
274
|
+
// форма изменена или снова стартовая
|
|
275
|
+
onFormDirty: (isDirty) => setDirty(isDirty),
|
|
276
|
+
// отправили без изменений
|
|
277
|
+
onEqual: () => close()
|
|
278
|
+
})
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
- `onDirty` сообщает о каждом поле, `onFormDirty` — о форме целиком: первое изменение и снятие последнего.
|
|
282
|
+
- `setAsDefault()` делает текущие значения стартовыми — после успешного сохранения.
|
|
283
|
+
- `reset(values)` ставит новые значения и делает их стартовыми; поле, которого нет в `values`, получает умолчание
|
|
284
|
+
компонента. `reset(values, { asDirty: true })` оставляет новые значения изменением.
|
|
285
|
+
- `setAsDefault()` и `reset(values)` сообщают «чисто» через `onDirty` и `onFormDirty`.
|
|
286
|
+
|
|
287
|
+
## Управление формой
|
|
288
|
+
|
|
289
|
+
`useForm` возвращает:
|
|
290
|
+
|
|
291
|
+
| Метод | Что делает |
|
|
292
|
+
| ----------------------------- | ---------------------------------------------------------------------- |
|
|
293
|
+
| `manager` | менеджер для `FormLayout` |
|
|
294
|
+
| `handleSubmit()` | проверка показанных полей и `onSubmit` (или `onEqual`) |
|
|
295
|
+
| `getValues()` | значения формы — то, что она показывает |
|
|
296
|
+
| `getValue(name)` | значение поля по полному пути (`company.name`) |
|
|
297
|
+
| `setValue(name, value)` | запись поля, как ввод пользователя |
|
|
298
|
+
| `reset(values, options?)` | новые значения, по умолчанию — стартовые |
|
|
299
|
+
| `setAsDefault()` | текущие значения — стартовые |
|
|
300
|
+
| `setError(name, { message })` | ошибка поля |
|
|
301
|
+
| `setFocus(name)` | фокус на поле |
|
|
302
|
+
| `subscribe(name, callback)` | подписка на поле; возвращает отписку |
|
|
303
|
+
| `subscribeAny(callback)` | подписка на любую правку; возвращает отписку |
|
|
304
|
+
| `getNames()` | полные пути всех полей схемы |
|
|
305
|
+
| `useValue(name)` | хук внутри `FormLayout`: значение поля с перерисовкой и типом из схемы |
|
|
306
|
+
|
|
307
|
+
## Внутри схемы: `useValue` и `useSetValue`
|
|
308
|
+
|
|
309
|
+
Компоненты раскладок и поля читают и пишут соседние поля по полному пути. Хуки берут форму из контекста, поэтому
|
|
310
|
+
работают внутри `FormLayout`:
|
|
311
|
+
|
|
312
|
+
```tsx
|
|
313
|
+
// подсказка, которая зависит от выбранной причины
|
|
314
|
+
const ReasonHint = createLayout(() => {
|
|
315
|
+
return () => {
|
|
316
|
+
const reason = useValue<Reason | null>('reason')
|
|
317
|
+
|
|
318
|
+
return (
|
|
319
|
+
<p className="hint">
|
|
320
|
+
{reason === 'scan' ? 'Переснимут только отмеченные' : 'Анкета вернётся на шаг'}
|
|
321
|
+
</p>
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
})()
|
|
325
|
+
|
|
326
|
+
// подстановка из списка в поле контакта
|
|
327
|
+
const ManagerPick = ({ managers }: { managers: Manager[] }) => {
|
|
328
|
+
const setName = useSetValue<string>('contact.name')
|
|
329
|
+
|
|
330
|
+
return <Menu items={managers} onSelect={(manager) => setName(manager.name)} />
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Типизированный `useValue` для схемы — `createUseValue<typeof scheme>()`.
|
|
335
|
+
|
|
336
|
+
## Поля, которые добавляет пользователь
|
|
337
|
+
|
|
338
|
+
```tsx
|
|
339
|
+
// Removable — своя раскладка с кнопкой удаления, AddMenu — меню ещё не добавленных полей
|
|
340
|
+
const Optional = createExtraForm({
|
|
341
|
+
getItems: (registry) => [
|
|
342
|
+
registry('phone')((name, remove) => Removable(remove)(TextForm(name, { placeholder: 'Телефон' }))),
|
|
343
|
+
registry('email')((name, remove) => Removable(remove)(TextForm(name, { placeholder: 'Почта' })))
|
|
344
|
+
],
|
|
345
|
+
getController: (append, visible) => <AddMenu hidden={visible} onSelect={append} />
|
|
346
|
+
})
|
|
58
347
|
```
|
|
348
|
+
|
|
349
|
+
Поле добавлено, пока у него есть значение: в `defaultValues` — показано сразу, убранное — изменение формы.
|
|
350
|
+
|
|
351
|
+
## 0.0.31
|
|
352
|
+
|
|
353
|
+
- `Condition` переименован в `OptionalCondition`: имя говорит, что скрытая ветка пропадает из значений.
|
|
354
|
+
- `NullableCondition`: скрытая ветка отдаёт `null` своим полям и контекстам, а не пропадает из значений; `null` у них
|
|
355
|
+
в `defaultValues` — отсутствие данных.
|
|
356
|
+
|
|
357
|
+
## 0.0.30
|
|
358
|
+
|
|
359
|
+
- Поле, снова показанное условием, начинает со стартового значения (`defaultValues`), а не с умолчания компонента.
|
|
360
|
+
- `onChange`, `getValues()` и отправка включают поля, которые изменение только что показало, — со стартовым значением,
|
|
361
|
+
до монтирования.
|
|
362
|
+
- `handleSubmit` проверяет только показанные поля: скрытое поле отправку не держит. Ошибка скрытого поля сбрасывается.
|
|
363
|
+
- Скрытое условием поле не считается изменённым — изменение несёт поле условия.
|
|
364
|
+
- `setAsDefault()` и `reset()` сообщают «чисто» через `onDirty` и `onFormDirty`.
|
package/dist/bundle.es.js
CHANGED
|
@@ -1,199 +1,237 @@
|
|
|
1
|
-
import { jsx as b, Fragment as
|
|
2
|
-
import { createContext as
|
|
3
|
-
import
|
|
4
|
-
const
|
|
5
|
-
const [,
|
|
6
|
-
if (!
|
|
1
|
+
import { jsx as b, Fragment as L, jsxs as _ } from "react/jsx-runtime";
|
|
2
|
+
import { createContext as z, useState as B, useContext as N, useMemo as $, useEffect as D, useCallback as m, useRef as G } from "react";
|
|
3
|
+
import P from "fast-deep-equal";
|
|
4
|
+
const w = z({}), M = (n) => {
|
|
5
|
+
const [, e] = B([]), r = N(w);
|
|
6
|
+
if (!r)
|
|
7
7
|
throw new Error("useValue cannot be used outside Form context");
|
|
8
|
-
const s =
|
|
9
|
-
const t =
|
|
8
|
+
const s = $(() => {
|
|
9
|
+
const t = r.getForm(n);
|
|
10
10
|
if (!t)
|
|
11
11
|
throw new Error(`form with name "${n}" doesnt exist in form`);
|
|
12
12
|
return t;
|
|
13
|
-
}, [
|
|
14
|
-
return
|
|
15
|
-
const t =
|
|
16
|
-
|
|
13
|
+
}, [r, n]);
|
|
14
|
+
return D(() => {
|
|
15
|
+
const t = r.subscribeToForm(n, () => {
|
|
16
|
+
e([]);
|
|
17
17
|
});
|
|
18
18
|
return () => {
|
|
19
19
|
t();
|
|
20
20
|
};
|
|
21
21
|
}, []), s.value;
|
|
22
|
-
},
|
|
23
|
-
const
|
|
24
|
-
if (!
|
|
22
|
+
}, k = (n) => {
|
|
23
|
+
const e = N(w);
|
|
24
|
+
if (!e)
|
|
25
25
|
throw new Error("useSetValue cannot be used outside Form context");
|
|
26
|
-
return (
|
|
27
|
-
|
|
26
|
+
return (r) => {
|
|
27
|
+
e.setValue(n, r);
|
|
28
28
|
};
|
|
29
|
-
},
|
|
30
|
-
const s =
|
|
31
|
-
return n(s) ? /* @__PURE__ */ b(
|
|
32
|
-
},
|
|
33
|
-
const [,
|
|
34
|
-
|
|
35
|
-
}), []),
|
|
36
|
-
(
|
|
37
|
-
if (
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
}, I = () => (n) => M(n), H = ({ canActivate: n, name: e, children: r }) => {
|
|
30
|
+
const s = M(e);
|
|
31
|
+
return n(s) ? /* @__PURE__ */ b(L, { children: r }) : null;
|
|
32
|
+
}, J = ({ item: { Form: n }, name: e }) => {
|
|
33
|
+
const [, r] = B([]), s = N(w), { unregistry: t } = $(() => s.registry(e, () => {
|
|
34
|
+
r([]);
|
|
35
|
+
}), []), u = m(
|
|
36
|
+
(y) => {
|
|
37
|
+
if (y && y.focus) {
|
|
38
|
+
const v = s.getForm(e);
|
|
39
|
+
v.focus = () => {
|
|
40
|
+
y.focus();
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
|
-
[
|
|
44
|
+
[e]
|
|
45
45
|
);
|
|
46
|
-
|
|
46
|
+
D(() => () => {
|
|
47
47
|
t();
|
|
48
48
|
}, []);
|
|
49
|
-
const { value:
|
|
49
|
+
const { value: d, error: h } = s.getForm(e);
|
|
50
50
|
return /* @__PURE__ */ b(
|
|
51
51
|
n,
|
|
52
52
|
{
|
|
53
53
|
field: {
|
|
54
|
-
value:
|
|
55
|
-
onChange: (
|
|
56
|
-
s.onChange(
|
|
54
|
+
value: d,
|
|
55
|
+
onChange: (y) => {
|
|
56
|
+
s.onChange(e, y);
|
|
57
57
|
},
|
|
58
58
|
onBlur: () => {
|
|
59
59
|
},
|
|
60
|
-
ref:
|
|
60
|
+
ref: u
|
|
61
61
|
},
|
|
62
62
|
isDirty: !1,
|
|
63
|
-
error:
|
|
63
|
+
error: h,
|
|
64
64
|
disabled: s.disabled
|
|
65
65
|
}
|
|
66
66
|
);
|
|
67
|
-
},
|
|
68
|
-
const { getController:
|
|
69
|
-
const
|
|
70
|
-
return s.forEach(({ name: i, getForm:
|
|
71
|
-
|
|
72
|
-
}),
|
|
73
|
-
}, []),
|
|
74
|
-
const
|
|
67
|
+
}, K = ({ item: n, path: e }) => {
|
|
68
|
+
const { getController: r, items: s } = n, t = N(w), u = $(() => {
|
|
69
|
+
const f = {};
|
|
70
|
+
return s.forEach(({ name: i, getForm: F }) => {
|
|
71
|
+
f[i] = F(i, () => j(i));
|
|
72
|
+
}), f;
|
|
73
|
+
}, []), d = m(() => {
|
|
74
|
+
const f = [];
|
|
75
75
|
return s.forEach(({ name: i }) => {
|
|
76
|
-
t.getForm([...
|
|
77
|
-
}),
|
|
78
|
-
}, []),
|
|
79
|
-
|
|
80
|
-
const { unregistry:
|
|
81
|
-
s.map(({ name: i }) => [...
|
|
76
|
+
t.getForm([...e, i].join(".")).value !== void 0 && f.push(i);
|
|
77
|
+
}), f;
|
|
78
|
+
}, []), h = $(() => d(), []), [y, v] = B(h);
|
|
79
|
+
D(() => {
|
|
80
|
+
const { unregistry: f } = t.registryExtraForm(
|
|
81
|
+
s.map(({ name: i }) => [...e, i].join(".")),
|
|
82
82
|
() => {
|
|
83
|
-
|
|
83
|
+
v(d());
|
|
84
84
|
}
|
|
85
85
|
);
|
|
86
86
|
return () => {
|
|
87
|
-
|
|
87
|
+
f();
|
|
88
88
|
};
|
|
89
89
|
}, []);
|
|
90
|
-
const
|
|
91
|
-
(
|
|
92
|
-
f
|
|
90
|
+
const x = m(
|
|
91
|
+
(f) => {
|
|
92
|
+
u[f] && !y.includes(f) && v((i) => [...i, f]);
|
|
93
93
|
},
|
|
94
|
-
[
|
|
95
|
-
),
|
|
96
|
-
|
|
94
|
+
[y]
|
|
95
|
+
), j = m((f) => {
|
|
96
|
+
v((i) => i.filter((F) => F !== f));
|
|
97
97
|
}, []);
|
|
98
|
-
return /* @__PURE__ */
|
|
99
|
-
|
|
100
|
-
const i = f
|
|
101
|
-
return /* @__PURE__ */ b(
|
|
98
|
+
return /* @__PURE__ */ _(L, { children: [
|
|
99
|
+
y.map((f) => {
|
|
100
|
+
const i = u[f];
|
|
101
|
+
return /* @__PURE__ */ b(A, { path: e, scheme: [i] }, `param-form--${f}`);
|
|
102
102
|
}),
|
|
103
|
-
|
|
103
|
+
r(x, y)
|
|
104
104
|
] });
|
|
105
|
-
},
|
|
106
|
-
|
|
105
|
+
}, A = ({ scheme: n, path: e }) => /* @__PURE__ */ b(L, { children: n.map((r, s) => r.type === "layout" ? /* @__PURE__ */ b(r.Layout, { children: /* @__PURE__ */ b(A, { path: e, scheme: r.childs }) }, `layout-form--${s}-${e.length}`) : r.type === "context" ? /* @__PURE__ */ b(
|
|
106
|
+
A,
|
|
107
107
|
{
|
|
108
|
-
path: [...
|
|
109
|
-
scheme:
|
|
108
|
+
path: [...e, r.context],
|
|
109
|
+
scheme: r.childs
|
|
110
110
|
},
|
|
111
|
-
`context-form--${s}-${
|
|
112
|
-
) :
|
|
113
|
-
|
|
111
|
+
`context-form--${s}-${r.context}-${e.length}`
|
|
112
|
+
) : r.type === "condition" ? /* @__PURE__ */ b(
|
|
113
|
+
H,
|
|
114
114
|
{
|
|
115
|
-
name:
|
|
116
|
-
canActivate:
|
|
117
|
-
children: /* @__PURE__ */ b(
|
|
115
|
+
name: r.depended,
|
|
116
|
+
canActivate: r.canActivate,
|
|
117
|
+
children: /* @__PURE__ */ b(A, { path: e, scheme: r.childs })
|
|
118
118
|
},
|
|
119
|
-
`condition--${s}-${
|
|
120
|
-
) :
|
|
121
|
-
|
|
119
|
+
`condition--${s}-${r.depended}-${e.length}`
|
|
120
|
+
) : r.type === "extra" ? /* @__PURE__ */ b(K, { path: e, item: r }, `partial-item--${s}-${e.length}`) : r.type === "visability" ? r.hidden ? null : /* @__PURE__ */ b(A, { path: e, scheme: r.childs }, `visability--${s}-${e.length}`) : /* @__PURE__ */ b(
|
|
121
|
+
J,
|
|
122
122
|
{
|
|
123
|
-
name: [...
|
|
124
|
-
item:
|
|
123
|
+
name: [...e, r.name].join("."),
|
|
124
|
+
item: r
|
|
125
125
|
},
|
|
126
|
-
`form-item--${s}-${
|
|
127
|
-
)) }),
|
|
126
|
+
`form-item--${s}-${r.name}-${e.length}`
|
|
127
|
+
)) }), Q = (n) => {
|
|
128
|
+
const e = {};
|
|
129
|
+
for (const r in n)
|
|
130
|
+
n[r] !== null && (e[r] = n[r]);
|
|
131
|
+
return e;
|
|
132
|
+
}, p = (n, e, r, s) => {
|
|
128
133
|
n.forEach((t) => {
|
|
129
|
-
if (t.type === "form" && s(t, [...
|
|
130
|
-
|
|
134
|
+
if (t.type === "form" && s(t, [...e, t.name].join("."), r[t.name]), t.type === "context") {
|
|
135
|
+
p(t.childs, [...e, t.context], r[t.context] ?? {}, s);
|
|
131
136
|
return;
|
|
132
137
|
}
|
|
133
|
-
if (t.type === "layout" || t.type === "
|
|
134
|
-
|
|
138
|
+
if (t.type === "layout" || t.type === "visability") {
|
|
139
|
+
p(t.childs, e, r, s);
|
|
135
140
|
return;
|
|
136
141
|
}
|
|
137
|
-
t.type === "
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
if (t.type === "condition") {
|
|
143
|
+
p(t.childs, e, t.nullable ? Q(r) : r, s);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
t.type === "extra" && t.items.forEach(({ getForm: u, name: d }) => {
|
|
147
|
+
p([u(d, () => {
|
|
148
|
+
})], e, r, s);
|
|
140
149
|
});
|
|
141
150
|
});
|
|
142
|
-
},
|
|
151
|
+
}, C = (n, e, r, s) => {
|
|
143
152
|
n.forEach((t) => {
|
|
144
|
-
if (t.type === "form") {
|
|
145
|
-
|
|
146
|
-
|
|
153
|
+
if (t.type === "form" && s([...e, t.name].join(".")), t.type === "context") {
|
|
154
|
+
C(t.childs, [...e, t.context], r, s);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (t.type === "layout") {
|
|
158
|
+
C(t.childs, e, r, s);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (t.type === "visability" && !t.hidden) {
|
|
162
|
+
C(t.childs, e, r, s);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (t.type === "condition" && t.canActivate(r[t.depended]?.value)) {
|
|
166
|
+
C(t.childs, e, r, s);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
t.type === "extra" && t.items.forEach(({ getForm: u, name: d }) => {
|
|
170
|
+
r[[...e, d].join(".")]?.value !== void 0 && C([u(d, () => {
|
|
171
|
+
})], e, r, s);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
}, U = (n, e) => {
|
|
175
|
+
n.forEach((r) => {
|
|
176
|
+
r.type === "form" && (e[r.name] = null), r.type === "context" && (e[r.context] = null), (r.type === "layout" || r.type === "condition" || r.type === "visability") && U(r.childs, e);
|
|
177
|
+
});
|
|
178
|
+
}, S = ({ scheme: n, values: e, path: r, forms: s, shown: t }) => {
|
|
179
|
+
n.forEach((u) => {
|
|
180
|
+
if (u.type === "form") {
|
|
181
|
+
const { value: d, startValue: h } = s[[...r, u.name].join(".")];
|
|
182
|
+
d !== void 0 && (e[u.name] = d), d === void 0 && t && (e[u.name] = h);
|
|
147
183
|
}
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
scheme:
|
|
151
|
-
path: [...
|
|
152
|
-
values:
|
|
153
|
-
forms: s
|
|
184
|
+
if (u.type === "context") {
|
|
185
|
+
e[u.context] = {}, S({
|
|
186
|
+
scheme: u.childs,
|
|
187
|
+
path: [...r, u.context],
|
|
188
|
+
values: e[u.context],
|
|
189
|
+
forms: s,
|
|
190
|
+
shown: t
|
|
154
191
|
});
|
|
155
192
|
return;
|
|
156
193
|
}
|
|
157
|
-
if (
|
|
158
|
-
|
|
194
|
+
if (u.type === "layout") {
|
|
195
|
+
S({ scheme: u.childs, path: r, values: e, forms: s, shown: t });
|
|
159
196
|
return;
|
|
160
197
|
}
|
|
161
|
-
if (
|
|
162
|
-
|
|
198
|
+
if (u.type === "visability") {
|
|
199
|
+
S({ scheme: u.childs, path: r, values: e, forms: s, shown: t && !u.hidden });
|
|
163
200
|
return;
|
|
164
201
|
}
|
|
165
|
-
if (
|
|
166
|
-
const
|
|
167
|
-
if (
|
|
168
|
-
|
|
202
|
+
if (u.type === "condition") {
|
|
203
|
+
const d = s[u.depended]?.value;
|
|
204
|
+
if (u.canActivate(d)) {
|
|
205
|
+
S({ scheme: u.childs, path: r, values: e, forms: s, shown: t });
|
|
169
206
|
return;
|
|
170
207
|
}
|
|
208
|
+
u.nullable && U(u.childs, e);
|
|
171
209
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
})], path:
|
|
210
|
+
u.type === "extra" && u.items.forEach(({ getForm: d, name: h }) => {
|
|
211
|
+
S({ scheme: [d(h, () => {
|
|
212
|
+
})], path: r, values: e, forms: s, shown: !1 });
|
|
175
213
|
});
|
|
176
214
|
});
|
|
177
|
-
},
|
|
178
|
-
const
|
|
179
|
-
return
|
|
180
|
-
},
|
|
181
|
-
const { onSubmit:
|
|
215
|
+
}, q = (n, e) => {
|
|
216
|
+
const r = {};
|
|
217
|
+
return S({ scheme: n, path: [], values: r, forms: e, shown: !0 }), r;
|
|
218
|
+
}, W = (n, e) => {
|
|
219
|
+
const { onSubmit: r, onChange: s, onEqual: t, disabled: u, onDirty: d, onFormDirty: h, onChangeEvent: y, defaultValues: v } = e, x = { onSubmit: r }, j = { onChange: s }, f = {
|
|
182
220
|
isActive: !1,
|
|
183
221
|
isSubmitted: !1,
|
|
184
222
|
dirtyCount: 0
|
|
185
|
-
}, i = {},
|
|
223
|
+
}, i = {}, F = /* @__PURE__ */ new Set(), E = {
|
|
186
224
|
subscribers: [],
|
|
187
225
|
names: {}
|
|
188
226
|
};
|
|
189
|
-
|
|
190
|
-
i[
|
|
227
|
+
p(n, [], v ?? {}, (o, a, c) => {
|
|
228
|
+
i[a] = {
|
|
191
229
|
error: null,
|
|
192
230
|
isDirty: !1,
|
|
193
|
-
value:
|
|
194
|
-
// текущее (динамическое) состояние поля. Значение равно переданному дефолтному, либо: определяется как
|
|
195
|
-
startValue:
|
|
196
|
-
// начальное (стартовое) значение (равно переданному дефолтному, либо значению формы по умолчанию).
|
|
231
|
+
value: c,
|
|
232
|
+
// текущее (динамическое) состояние поля. Значение равно переданному дефолтному, либо: определяется как стартовое значение в момент монтирования поля, а до этого - undefined. Поле, которое скрыло условие, значения не имеет.
|
|
233
|
+
startValue: c ?? o.defaultValue,
|
|
234
|
+
// начальное (стартовое) значение (равно переданному дефолтному, либо значению формы по умолчанию). С него начинает поле при монтировании, в том числе снова показанное условием; исходя из сравнения текущего значения со стартовым, можно понять, модифицированно ли поле
|
|
197
235
|
defaultValue: o.defaultValue,
|
|
198
236
|
// дефолтное значение компонента формы
|
|
199
237
|
rerender: () => {
|
|
@@ -202,98 +240,100 @@ const A = O({}), N = (n) => {
|
|
|
202
240
|
validate: o.validate
|
|
203
241
|
};
|
|
204
242
|
});
|
|
205
|
-
const
|
|
206
|
-
|
|
243
|
+
const T = (o, a) => {
|
|
244
|
+
d?.({ name: o, isDirty: a }), a && f.dirtyCount === 0 && h?.(!0), !a && f.dirtyCount === 1 && h?.(!1), f.dirtyCount += a ? 1 : -1;
|
|
245
|
+
}, O = () => {
|
|
246
|
+
for (const o in i)
|
|
247
|
+
i[o].isDirty && (T(o, !1), i[o].isDirty = !1);
|
|
207
248
|
};
|
|
208
249
|
return {
|
|
209
|
-
submitRef:
|
|
210
|
-
changeRef:
|
|
250
|
+
submitRef: x,
|
|
251
|
+
changeRef: j,
|
|
211
252
|
scheme: n,
|
|
212
|
-
disabled:
|
|
253
|
+
disabled: u,
|
|
213
254
|
activate() {
|
|
214
|
-
|
|
255
|
+
f.isActive = !0;
|
|
215
256
|
},
|
|
216
257
|
disactivate() {
|
|
217
|
-
|
|
258
|
+
f.isActive = !1;
|
|
218
259
|
},
|
|
219
|
-
setError(o,
|
|
220
|
-
const
|
|
221
|
-
|
|
260
|
+
setError(o, a) {
|
|
261
|
+
const c = this.getForm(o);
|
|
262
|
+
c && (c.error = {
|
|
222
263
|
error: !0,
|
|
223
|
-
messages: [
|
|
224
|
-
},
|
|
264
|
+
messages: [a.message]
|
|
265
|
+
}, c.rerender());
|
|
225
266
|
},
|
|
226
267
|
setFocus(o) {
|
|
227
|
-
const
|
|
228
|
-
|
|
268
|
+
const a = this.getForm(o);
|
|
269
|
+
a && a.focus && a.focus();
|
|
229
270
|
},
|
|
230
|
-
setValue(o,
|
|
231
|
-
const
|
|
232
|
-
|
|
271
|
+
setValue(o, a) {
|
|
272
|
+
const c = this.getForm(o);
|
|
273
|
+
c && c.value !== a && this.onChange(o, a);
|
|
233
274
|
},
|
|
234
275
|
getValues() {
|
|
235
|
-
return
|
|
276
|
+
return q(n, i);
|
|
236
277
|
},
|
|
237
278
|
async handleSubmit() {
|
|
238
|
-
if (
|
|
279
|
+
if (u)
|
|
239
280
|
return;
|
|
240
|
-
|
|
241
|
-
let o = !1,
|
|
242
|
-
|
|
243
|
-
const
|
|
244
|
-
if (
|
|
245
|
-
const g =
|
|
246
|
-
g && (
|
|
281
|
+
f.isSubmitted = !0;
|
|
282
|
+
let o = !1, a = !1;
|
|
283
|
+
if (C(n, [], i, (c) => {
|
|
284
|
+
const l = i[c];
|
|
285
|
+
if (l.value !== void 0) {
|
|
286
|
+
const g = l.validate(l.value);
|
|
287
|
+
g && (a = !0, l.error = g, l.rerender(), !o && l.focus && (l.focus(), o = !0));
|
|
247
288
|
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (l.dirtyCount === 0 && t) {
|
|
289
|
+
}), !a) {
|
|
290
|
+
if (f.dirtyCount === 0 && t) {
|
|
251
291
|
t();
|
|
252
292
|
return;
|
|
253
293
|
}
|
|
254
|
-
if (!
|
|
294
|
+
if (!x.onSubmit)
|
|
255
295
|
return;
|
|
256
|
-
const
|
|
257
|
-
await
|
|
258
|
-
setError: (
|
|
259
|
-
const
|
|
260
|
-
|
|
296
|
+
const c = q(n, i);
|
|
297
|
+
await x.onSubmit(c, {
|
|
298
|
+
setError: (l, g) => {
|
|
299
|
+
const V = this.getForm(l);
|
|
300
|
+
V.error = {
|
|
261
301
|
error: !0,
|
|
262
302
|
messages: [g.message]
|
|
263
|
-
},
|
|
303
|
+
}, V.rerender();
|
|
264
304
|
}
|
|
265
|
-
}).catch((
|
|
266
|
-
console.log("[formkit] submit exception:",
|
|
305
|
+
}).catch((l) => {
|
|
306
|
+
console.log("[formkit] submit exception:", l);
|
|
267
307
|
});
|
|
268
308
|
}
|
|
269
309
|
},
|
|
270
|
-
reset(o, { asDirty:
|
|
271
|
-
|
|
272
|
-
if (g === void 0 && i[
|
|
310
|
+
reset(o, { asDirty: a }) {
|
|
311
|
+
p(n, [], o, (c, l, g) => {
|
|
312
|
+
if (g === void 0 && i[l].value === void 0)
|
|
273
313
|
return;
|
|
274
|
-
if (
|
|
275
|
-
i[
|
|
314
|
+
if (E.names[l] && g === void 0) {
|
|
315
|
+
i[l].value = void 0;
|
|
276
316
|
return;
|
|
277
317
|
}
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
}),
|
|
281
|
-
|
|
318
|
+
const V = g ?? c.defaultValue;
|
|
319
|
+
a || (i[l].startValue = V), i[l].value !== V && this.onChange(l, V);
|
|
320
|
+
}), a || (O(), f.isSubmitted = !1), E.subscribers.forEach(({ visualizeEvalueatedForms: c }) => {
|
|
321
|
+
c();
|
|
282
322
|
});
|
|
283
323
|
},
|
|
284
324
|
setAsDefault() {
|
|
285
|
-
|
|
286
|
-
i[
|
|
287
|
-
}),
|
|
325
|
+
p(n, [], {}, (o, a) => {
|
|
326
|
+
i[a].startValue = i[a].value ?? i[a].defaultValue;
|
|
327
|
+
}), O(), f.isSubmitted = !1;
|
|
288
328
|
},
|
|
289
|
-
registry(o,
|
|
290
|
-
return i[o].rerender =
|
|
329
|
+
registry(o, a) {
|
|
330
|
+
return i[o].rerender = a, i[o].value === void 0 && (i[o].value = E.names[o] ? i[o].defaultValue : i[o].startValue), {
|
|
291
331
|
unregistry() {
|
|
292
332
|
if (i[o].rerender = () => {
|
|
293
|
-
}, i[o].focus = void 0,
|
|
294
|
-
i[o].value = void 0;
|
|
295
|
-
const
|
|
296
|
-
i[o].isDirty !==
|
|
333
|
+
}, i[o].focus = void 0, f.isActive) {
|
|
334
|
+
i[o].value = void 0, i[o].error = null;
|
|
335
|
+
const c = E.names[o] ? !P(i[o].startValue, i[o].defaultValue) : !1;
|
|
336
|
+
i[o].isDirty !== c && T(o, c), i[o].isDirty = c;
|
|
297
337
|
}
|
|
298
338
|
}
|
|
299
339
|
};
|
|
@@ -301,52 +341,52 @@ const A = O({}), N = (n) => {
|
|
|
301
341
|
getForm(o) {
|
|
302
342
|
return i[o];
|
|
303
343
|
},
|
|
304
|
-
subscribeToForm(o,
|
|
305
|
-
const
|
|
306
|
-
return
|
|
307
|
-
|
|
344
|
+
subscribeToForm(o, a) {
|
|
345
|
+
const c = { callback: a }, l = this.getForm(o);
|
|
346
|
+
return l.subscribers.push(c), () => {
|
|
347
|
+
l.subscribers = l.subscribers.filter((g) => g !== c);
|
|
308
348
|
};
|
|
309
349
|
},
|
|
310
350
|
subscribeToAny(o) {
|
|
311
|
-
return
|
|
312
|
-
|
|
351
|
+
return F.add(o), () => {
|
|
352
|
+
F.delete(o);
|
|
313
353
|
};
|
|
314
354
|
},
|
|
315
355
|
getNames() {
|
|
316
356
|
return Object.keys(i);
|
|
317
357
|
},
|
|
318
|
-
registryExtraForm(o,
|
|
319
|
-
const
|
|
320
|
-
return o.forEach((
|
|
321
|
-
|
|
322
|
-
}),
|
|
358
|
+
registryExtraForm(o, a) {
|
|
359
|
+
const c = { visualizeEvalueatedForms: a };
|
|
360
|
+
return o.forEach((l) => {
|
|
361
|
+
E.names[l] = !0;
|
|
362
|
+
}), E.subscribers.push(c), {
|
|
323
363
|
unregistry() {
|
|
324
|
-
|
|
364
|
+
E.subscribers = E.subscribers.filter((l) => l !== c);
|
|
325
365
|
}
|
|
326
366
|
};
|
|
327
367
|
},
|
|
328
|
-
onChange(o,
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
const g =
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
}),
|
|
335
|
-
|
|
336
|
-
}),
|
|
368
|
+
onChange(o, a) {
|
|
369
|
+
const c = this.getForm(o), l = !P(a, c.startValue);
|
|
370
|
+
c.isDirty !== l && T(o, l), c.isDirty = l, y?.({ name: o, value: a }), (c.error || f.isSubmitted) && (c.error = c.validate(a) || null);
|
|
371
|
+
const g = c.value;
|
|
372
|
+
c.value = a, c.rerender(), c.subscribers.forEach(({ callback: V }) => {
|
|
373
|
+
V(a, g);
|
|
374
|
+
}), F.forEach((V) => {
|
|
375
|
+
V();
|
|
376
|
+
}), j.onChange?.(q(n, i));
|
|
337
377
|
}
|
|
338
378
|
};
|
|
339
|
-
},
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
const s =
|
|
343
|
-
return
|
|
344
|
-
|
|
345
|
-
}, [
|
|
379
|
+
}, rr = (n, e) => {
|
|
380
|
+
const r = G(null);
|
|
381
|
+
r.current === null && (r.current = W(n, e));
|
|
382
|
+
const s = r.current;
|
|
383
|
+
return D(() => {
|
|
384
|
+
r.current && (r.current.submitRef.onSubmit = e.onSubmit, r.current.changeRef.onChange = e.onChange);
|
|
385
|
+
}, [e.onSubmit, e.onChange]), {
|
|
346
386
|
manager: s,
|
|
347
|
-
useValue: (t) =>
|
|
348
|
-
reset: (t,
|
|
349
|
-
s.reset(t,
|
|
387
|
+
useValue: (t) => M(t),
|
|
388
|
+
reset: (t, u = {}) => {
|
|
389
|
+
s.reset(t, u);
|
|
350
390
|
},
|
|
351
391
|
setAsDefault: () => {
|
|
352
392
|
s.setAsDefault();
|
|
@@ -354,11 +394,11 @@ const A = O({}), N = (n) => {
|
|
|
354
394
|
setFocus: (t) => {
|
|
355
395
|
s.setFocus(t);
|
|
356
396
|
},
|
|
357
|
-
setError: (t,
|
|
358
|
-
s.setError(t,
|
|
397
|
+
setError: (t, u) => {
|
|
398
|
+
s.setError(t, u);
|
|
359
399
|
},
|
|
360
|
-
setValue: (t,
|
|
361
|
-
s.setValue(t,
|
|
400
|
+
setValue: (t, u) => {
|
|
401
|
+
s.setValue(t, u);
|
|
362
402
|
},
|
|
363
403
|
getValue: (t) => s.getForm(t).value,
|
|
364
404
|
getValues: () => s.getValues(),
|
|
@@ -366,91 +406,99 @@ const A = O({}), N = (n) => {
|
|
|
366
406
|
await s.handleSubmit();
|
|
367
407
|
},
|
|
368
408
|
// prettier-ignore
|
|
369
|
-
subscribe: (t,
|
|
409
|
+
subscribe: (t, u) => s.subscribeToForm(t, u),
|
|
370
410
|
// подписка на любое изменение значений формы (для гейтов поверх всех полей)
|
|
371
411
|
subscribeAny: (t) => s.subscribeToAny(t),
|
|
372
412
|
// плоский список имён всех полей (dotted-пути; вложенные context раскрыты)
|
|
373
413
|
getNames: () => s.getNames()
|
|
374
414
|
};
|
|
375
|
-
},
|
|
415
|
+
}, er = ({ manager: n }) => ($(() => {
|
|
376
416
|
n.activate();
|
|
377
|
-
}, []),
|
|
417
|
+
}, []), D(() => () => {
|
|
378
418
|
n.disactivate();
|
|
379
|
-
}, []), /* @__PURE__ */ b(
|
|
419
|
+
}, []), /* @__PURE__ */ b(w.Provider, { value: n, children: /* @__PURE__ */ b(A, { scheme: n.scheme, path: [] }) })), R = (n) => {
|
|
380
420
|
try {
|
|
381
421
|
n();
|
|
382
|
-
} catch (
|
|
383
|
-
return
|
|
422
|
+
} catch (e) {
|
|
423
|
+
return e && typeof e == "string" ? {
|
|
384
424
|
error: !0,
|
|
385
|
-
messages: [
|
|
386
|
-
} :
|
|
425
|
+
messages: [e]
|
|
426
|
+
} : e instanceof Array && e.every((r) => r && typeof r == "string") ? {
|
|
387
427
|
error: !0,
|
|
388
|
-
messages:
|
|
428
|
+
messages: e
|
|
389
429
|
} : {
|
|
390
430
|
error: !0
|
|
391
431
|
};
|
|
392
432
|
}
|
|
393
|
-
},
|
|
394
|
-
const s = n.getRequireCheck(
|
|
433
|
+
}, tr = (n) => (e, r) => {
|
|
434
|
+
const s = n.getRequireCheck(r), { $rules: t = {}, ...u } = r, { validate: d, required: h } = t;
|
|
395
435
|
return {
|
|
396
436
|
type: "form",
|
|
397
|
-
name:
|
|
437
|
+
name: e,
|
|
398
438
|
defaultValue: n.defaultValue,
|
|
399
|
-
Form: n.getForm(
|
|
400
|
-
validate: (
|
|
401
|
-
if (
|
|
402
|
-
const
|
|
403
|
-
if (
|
|
404
|
-
return
|
|
405
|
-
if (
|
|
406
|
-
const
|
|
407
|
-
if (
|
|
408
|
-
return
|
|
439
|
+
Form: n.getForm(u),
|
|
440
|
+
validate: (y) => {
|
|
441
|
+
if (h) {
|
|
442
|
+
const v = R(() => s(y));
|
|
443
|
+
if (v)
|
|
444
|
+
return v;
|
|
445
|
+
if (d) {
|
|
446
|
+
const x = R(() => d(y));
|
|
447
|
+
if (x)
|
|
448
|
+
return x;
|
|
409
449
|
}
|
|
410
450
|
return;
|
|
411
451
|
}
|
|
412
|
-
if (
|
|
413
|
-
const
|
|
414
|
-
if (
|
|
415
|
-
return
|
|
452
|
+
if (d && !R(() => s(y))) {
|
|
453
|
+
const x = R(() => d(y));
|
|
454
|
+
if (x)
|
|
455
|
+
return x;
|
|
416
456
|
}
|
|
417
457
|
}
|
|
418
458
|
};
|
|
419
|
-
},
|
|
459
|
+
}, nr = (n) => (e) => (...r) => ({
|
|
420
460
|
type: "layout",
|
|
421
|
-
Layout: n(
|
|
422
|
-
childs:
|
|
423
|
-
}),
|
|
461
|
+
Layout: n(e),
|
|
462
|
+
childs: r
|
|
463
|
+
}), sr = ({
|
|
424
464
|
getItems: n,
|
|
425
|
-
getController:
|
|
465
|
+
getController: e
|
|
426
466
|
}) => ({
|
|
427
467
|
type: "extra",
|
|
428
|
-
items: n((
|
|
429
|
-
getController:
|
|
430
|
-
}),
|
|
468
|
+
items: n((r) => (s) => ({ type: "registry", name: r, getForm: s })),
|
|
469
|
+
getController: e
|
|
470
|
+
}), or = (n) => (...e) => ({
|
|
431
471
|
type: "context",
|
|
432
472
|
context: n,
|
|
473
|
+
childs: e
|
|
474
|
+
}), ir = (n, e) => (...r) => ({
|
|
475
|
+
type: "condition",
|
|
476
|
+
depended: n,
|
|
477
|
+
canActivate: e.canActivate,
|
|
478
|
+
nullable: !1,
|
|
433
479
|
childs: r
|
|
434
|
-
}),
|
|
480
|
+
}), ur = (n, e) => (...r) => ({
|
|
435
481
|
type: "condition",
|
|
436
482
|
depended: n,
|
|
437
|
-
canActivate:
|
|
438
|
-
|
|
439
|
-
|
|
483
|
+
canActivate: e.canActivate,
|
|
484
|
+
nullable: !0,
|
|
485
|
+
childs: r
|
|
486
|
+
}), cr = ({ hidden: n }) => (...e) => ({
|
|
440
487
|
type: "visability",
|
|
441
488
|
hidden: n ?? !1,
|
|
442
|
-
childs:
|
|
489
|
+
childs: e
|
|
443
490
|
});
|
|
444
491
|
export {
|
|
445
|
-
|
|
446
|
-
er as
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
492
|
+
or as Context,
|
|
493
|
+
er as FormLayout,
|
|
494
|
+
ur as NullableCondition,
|
|
495
|
+
ir as OptionalCondition,
|
|
496
|
+
cr as Visablility,
|
|
497
|
+
sr as createExtraForm,
|
|
498
|
+
tr as createForm,
|
|
499
|
+
nr as createLayout,
|
|
500
|
+
I as createUseValue,
|
|
501
|
+
rr as useForm,
|
|
502
|
+
k as useSetValue,
|
|
503
|
+
M as useValue
|
|
456
504
|
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { SchemeItems } from '../types';
|
|
2
|
-
|
|
3
|
-
export declare const Condition: (depended: string, props: {
|
|
2
|
+
interface ConditionProps {
|
|
4
3
|
canActivate: (value: any) => boolean;
|
|
5
|
-
}
|
|
4
|
+
}
|
|
5
|
+
export declare const Context: <N extends string>(context: N) => <T extends SchemeItems.All[]>(...childs: T) => SchemeItems.Context<N, T>;
|
|
6
|
+
export declare const OptionalCondition: (depended: string, props: ConditionProps) => <T extends SchemeItems.All[]>(...childs: T) => SchemeItems.Condition<T, false>;
|
|
7
|
+
export declare const NullableCondition: (depended: string, props: ConditionProps) => <T extends SchemeItems.All[]>(...childs: T) => SchemeItems.Condition<T, true>;
|
|
6
8
|
export declare const Visablility: ({ hidden }: {
|
|
7
9
|
hidden?: boolean;
|
|
8
10
|
}) => <T extends SchemeItems.All[]>(...childs: T) => SchemeItems.Visablility<T>;
|
|
11
|
+
export {};
|
package/dist/core/extract.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { SchemeItems } from './types';
|
|
2
2
|
import { Compute, UnionToIntersection } from '../utils/typescript';
|
|
3
|
+
type OrNull<T> = {
|
|
4
|
+
[K in keyof T]: T[K] | null;
|
|
5
|
+
};
|
|
3
6
|
type ExtractValue<T> = T extends SchemeItems.Form<infer N, infer V> ? {
|
|
4
7
|
[K in N]: V;
|
|
5
8
|
} : T extends SchemeItems.Layout<infer C> ? ExtractValue<C[number]> : T extends SchemeItems.Context<infer N, infer C> ? {
|
|
6
9
|
[K in N]: Compute<UnionToIntersection<ExtractValue<C[number]>>>;
|
|
7
|
-
} : T extends SchemeItems.Condition<infer C> ? Partial<ExtractValue<C[number]>> : T extends SchemeItems.Visablility<infer C> ? Partial<ExtractValue<C[number]>> : T extends SchemeItems.Extra<string, infer C> ? Partial<ExtractValue<ReturnType<C[number]['getForm']>>> : never;
|
|
10
|
+
} : T extends SchemeItems.Condition<infer C, true> ? OrNull<ExtractValue<C[number]>> : T extends SchemeItems.Condition<infer C> ? Partial<ExtractValue<C[number]>> : T extends SchemeItems.Visablility<infer C> ? Partial<ExtractValue<C[number]>> : T extends SchemeItems.Extra<string, infer C> ? Partial<ExtractValue<ReturnType<C[number]['getForm']>>> : never;
|
|
8
11
|
type ExtractValues<T> = Compute<UnionToIntersection<ExtractValue<T>>>;
|
|
9
12
|
type ExtractFlatValue<T, A extends string | null> = T extends SchemeItems.Form<infer N, infer V> ? {
|
|
10
13
|
[K in A extends null ? N : `${A}.${N}`]: V;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -33,10 +33,11 @@ export declare namespace SchemeItems {
|
|
|
33
33
|
name: N;
|
|
34
34
|
getForm: <Q extends N>(name: Q, remove: () => void) => T;
|
|
35
35
|
}
|
|
36
|
-
interface Condition<T extends All[] = All[]> {
|
|
36
|
+
interface Condition<T extends All[] = All[], Nullable extends boolean = boolean> {
|
|
37
37
|
type: 'condition';
|
|
38
38
|
depended: string;
|
|
39
39
|
canActivate: (value: any) => boolean;
|
|
40
|
+
nullable: Nullable;
|
|
40
41
|
childs: T;
|
|
41
42
|
}
|
|
42
43
|
interface Visablility<T extends All[] = All[]> {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { Forms } from './manager';
|
|
1
2
|
import { FieldValues } from '../types';
|
|
2
3
|
import { SchemeItems } from '../core/types';
|
|
3
4
|
type cb = (item: SchemeItems.Form, name: string, value?: any) => void;
|
|
5
|
+
type shownCb = (name: string) => void;
|
|
4
6
|
declare const readScheme: (scheme: SchemeItems.All[], path: string[], values: FieldValues, callback: cb) => void;
|
|
5
|
-
|
|
7
|
+
declare const readShown: (scheme: SchemeItems.All[], path: string[], forms: Forms, callback: shownCb) => void;
|
|
8
|
+
export { readScheme, readShown };
|
package/package.json
CHANGED
package/dist/Condition.d.ts
DELETED