@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 CHANGED
@@ -1,58 +1,364 @@
1
- ## Create form primitives
1
+ # @companix/formkit
2
+
3
+ Формы на React одной декларативной схемой. Поля, раскладка, условия и проверка описываются деревом из обычных вызовов
4
+ функций, а значения формы TypeScript выводит из самой схемы — без ручных интерфейсов, `useState` на каждое поле и
5
+ `register` в разметке.
2
6
 
3
7
  ```tsx
4
- const SelectForm = (name: string) => {
5
- // select form code
6
- }
7
- const InputForm = (name: string) => {
8
- // input form code
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
- ## Create layouts
43
+ Нужен React 18.
44
+
45
+ ## Форма за минуту
13
46
 
14
47
  ```tsx
15
- export const Label = createLayout((label: React.ReactNode) => {
16
- return ({ children }) => {
17
- return <FormGroup label={label}>{children}</FormGroup>
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
- export const Double = createLayout(() => {
79
+ // раскладка: подпись над полем
80
+ const Label = createLayout((text: string) => {
22
81
  return ({ children }) => {
23
- return <div className="form-double-primitive">{children}</div>
82
+ return (
83
+ <label className="label">
84
+ <span>{text}</span>
85
+ {children}
86
+ </label>
87
+ )
24
88
  }
25
89
  })
26
90
 
27
- export const Splitter = createLayout(() => {
28
- return () => {
29
- return <div className="form-splitter" />
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
- ## Create a scheme
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
- ```ts
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
- Label('Имя')(
39
- SelectForm('name', {
40
- placeholder: 'Введите имя',
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`.
@@ -0,0 +1,7 @@
1
+ interface Props {
2
+ name: string;
3
+ canActivate: (value: any) => boolean;
4
+ children: React.ReactNode;
5
+ }
6
+ export declare const ConditionBranch: ({ canActivate, name, children }: Props) => import("react/jsx-runtime").JSX.Element | null;
7
+ export {};
package/dist/bundle.es.js CHANGED
@@ -1,199 +1,237 @@
1
- import { jsx as b, Fragment as q, jsxs as P } from "react/jsx-runtime";
2
- import { createContext as O, useState as L, useContext as R, useMemo as p, useEffect as $, useCallback as j, useRef as U } from "react";
3
- import M from "fast-deep-equal";
4
- const A = O({}), N = (n) => {
5
- const [, r] = L([]), e = R(A);
6
- if (!e)
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 = p(() => {
9
- const t = e.getForm(n);
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
- }, [e, n]);
14
- return $(() => {
15
- const t = e.subscribeToForm(n, () => {
16
- r([]);
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
- }, W = (n) => {
23
- const r = R(A);
24
- if (!r)
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 (e) => {
27
- r.setValue(n, e);
26
+ return (r) => {
27
+ e.setValue(n, r);
28
28
  };
29
- }, X = () => (n) => N(n), _ = ({ canActivate: n, name: r, children: e }) => {
30
- const s = N(r);
31
- return n(s) ? /* @__PURE__ */ b(q, { children: e }) : null;
32
- }, z = ({ item: { Form: n }, name: r }) => {
33
- const [, e] = L([]), s = R(A), { unregistry: t } = p(() => s.registry(r, () => {
34
- e([]);
35
- }), []), f = j(
36
- (d) => {
37
- if (d && d.focus) {
38
- const h = s.getForm(r);
39
- h.focus = () => {
40
- d.focus();
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
- [r]
44
+ [e]
45
45
  );
46
- $(() => () => {
46
+ D(() => () => {
47
47
  t();
48
48
  }, []);
49
- const { value: y, error: m } = s.getForm(r);
49
+ const { value: d, error: h } = s.getForm(e);
50
50
  return /* @__PURE__ */ b(
51
51
  n,
52
52
  {
53
53
  field: {
54
- value: y,
55
- onChange: (d) => {
56
- s.onChange(r, d);
54
+ value: d,
55
+ onChange: (y) => {
56
+ s.onChange(e, y);
57
57
  },
58
58
  onBlur: () => {
59
59
  },
60
- ref: f
60
+ ref: u
61
61
  },
62
62
  isDirty: !1,
63
- error: m,
63
+ error: h,
64
64
  disabled: s.disabled
65
65
  }
66
66
  );
67
- }, G = ({ item: n, path: r }) => {
68
- const { getController: e, items: s } = n, t = R(A), f = p(() => {
69
- const l = {};
70
- return s.forEach(({ name: i, getForm: x }) => {
71
- l[i] = x(i, () => D(i));
72
- }), l;
73
- }, []), y = j(() => {
74
- const l = [];
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([...r, i].join(".")).value !== void 0 && l.push(i);
77
- }), l;
78
- }, []), m = p(() => y(), []), [d, h] = L(m);
79
- $(() => {
80
- const { unregistry: l } = t.registryExtraForm(
81
- s.map(({ name: i }) => [...r, i].join(".")),
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
- h(y());
83
+ v(d());
84
84
  }
85
85
  );
86
86
  return () => {
87
- l();
87
+ f();
88
88
  };
89
89
  }, []);
90
- const v = j(
91
- (l) => {
92
- f[l] && !d.includes(l) && h((i) => [...i, l]);
90
+ const x = m(
91
+ (f) => {
92
+ u[f] && !y.includes(f) && v((i) => [...i, f]);
93
93
  },
94
- [d]
95
- ), D = j((l) => {
96
- h((i) => i.filter((x) => x !== l));
94
+ [y]
95
+ ), j = m((f) => {
96
+ v((i) => i.filter((F) => F !== f));
97
97
  }, []);
98
- return /* @__PURE__ */ P(q, { children: [
99
- d.map((l) => {
100
- const i = f[l];
101
- return /* @__PURE__ */ b(C, { path: r, scheme: [i] }, `param-form--${l}`);
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
- e(v, d)
103
+ r(x, y)
104
104
  ] });
105
- }, C = ({ scheme: n, path: r }) => /* @__PURE__ */ b(q, { children: n.map((e, s) => e.type === "layout" ? /* @__PURE__ */ b(e.Layout, { children: /* @__PURE__ */ b(C, { path: r, scheme: e.childs }) }, `layout-form--${s}-${r.length}`) : e.type === "context" ? /* @__PURE__ */ b(
106
- C,
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: [...r, e.context],
109
- scheme: e.childs
108
+ path: [...e, r.context],
109
+ scheme: r.childs
110
110
  },
111
- `context-form--${s}-${e.context}-${r.length}`
112
- ) : e.type === "condition" ? /* @__PURE__ */ b(
113
- _,
111
+ `context-form--${s}-${r.context}-${e.length}`
112
+ ) : r.type === "condition" ? /* @__PURE__ */ b(
113
+ H,
114
114
  {
115
- name: e.depended,
116
- canActivate: e.canActivate,
117
- children: /* @__PURE__ */ b(C, { path: r, scheme: e.childs })
115
+ name: r.depended,
116
+ canActivate: r.canActivate,
117
+ children: /* @__PURE__ */ b(A, { path: e, scheme: r.childs })
118
118
  },
119
- `condition--${s}-${e.depended}-${r.length}`
120
- ) : e.type === "extra" ? /* @__PURE__ */ b(G, { path: r, item: e }, `partial-item--${s}-${r.length}`) : e.type === "visability" ? e.hidden ? null : /* @__PURE__ */ b(C, { path: r, scheme: e.childs }, `visability--${s}-${r.length}`) : /* @__PURE__ */ b(
121
- z,
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: [...r, e.name].join("."),
124
- item: e
123
+ name: [...e, r.name].join("."),
124
+ item: r
125
125
  },
126
- `form-item--${s}-${e.name}-${r.length}`
127
- )) }), S = (n, r, e, s) => {
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, [...r, t.name].join("."), e[t.name]), t.type === "context") {
130
- S(t.childs, [...r, t.context], e[t.context] ?? {}, s);
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 === "condition" || t.type === "visability") {
134
- S(t.childs, r, e, s);
138
+ if (t.type === "layout" || t.type === "visability") {
139
+ p(t.childs, e, r, s);
135
140
  return;
136
141
  }
137
- t.type === "extra" && t.items.forEach(({ getForm: f, name: y }) => {
138
- S([f(y, () => {
139
- })], r, e, s);
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
- }, E = ({ scheme: n, values: r, path: e, forms: s }) => {
151
+ }, C = (n, e, r, s) => {
143
152
  n.forEach((t) => {
144
- if (t.type === "form") {
145
- const f = [...e, t.name].join(".");
146
- s[f].value !== void 0 && (r[t.name] = s[f].value);
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 (t.type === "context") {
149
- r[t.context] = {}, E({
150
- scheme: t.childs,
151
- path: [...e, t.context],
152
- values: r[t.context],
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 (t.type === "layout") {
158
- E({ scheme: t.childs, path: e, values: r, forms: s });
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 (t.type === "visability") {
162
- E({ scheme: t.childs, path: e, values: r, forms: s });
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 (t.type === "condition") {
166
- const f = s[t.depended]?.value;
167
- if (t.canActivate(f)) {
168
- E({ scheme: t.childs, path: e, values: r, forms: s });
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
- t.type === "extra" && t.items.forEach(({ getForm: f, name: y }) => {
173
- E({ scheme: [f(y, () => {
174
- })], path: e, values: r, forms: s });
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
- }, T = (n, r) => {
178
- const e = {};
179
- return E({ scheme: n, path: [], values: e, forms: r }), e;
180
- }, H = (n, r) => {
181
- const { onSubmit: e, onChange: s, onEqual: t, disabled: f, onDirty: y, onFormDirty: m, onChangeEvent: d, defaultValues: h } = r, v = { onSubmit: e }, D = { onChange: s }, l = {
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 = {}, x = /* @__PURE__ */ new Set(), V = {
223
+ }, i = {}, F = /* @__PURE__ */ new Set(), E = {
186
224
  subscribers: [],
187
225
  names: {}
188
226
  };
189
- S(n, [], h ?? {}, (o, c, u) => {
190
- i[c] = {
227
+ p(n, [], v ?? {}, (o, a, c) => {
228
+ i[a] = {
191
229
  error: null,
192
230
  isDirty: !1,
193
- value: u,
194
- // текущее (динамическое) состояние поля. Значение равно переданному дефолтному, либо: определяется как дефолтное значение компонента формы в момент его монтирования, а до этого - undefined.
195
- startValue: u ?? o.defaultValue,
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 B = (o, c) => {
206
- y?.({ name: o, isDirty: c }), c && l.dirtyCount === 0 && m?.(!0), !c && l.dirtyCount === 1 && m?.(!1), l.dirtyCount += c ? 1 : -1;
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: v,
210
- changeRef: D,
250
+ submitRef: x,
251
+ changeRef: j,
211
252
  scheme: n,
212
- disabled: f,
253
+ disabled: u,
213
254
  activate() {
214
- l.isActive = !0;
255
+ f.isActive = !0;
215
256
  },
216
257
  disactivate() {
217
- l.isActive = !1;
258
+ f.isActive = !1;
218
259
  },
219
- setError(o, c) {
220
- const u = this.getForm(o);
221
- u && (u.error = {
260
+ setError(o, a) {
261
+ const c = this.getForm(o);
262
+ c && (c.error = {
222
263
  error: !0,
223
- messages: [c.message]
224
- }, u.rerender());
264
+ messages: [a.message]
265
+ }, c.rerender());
225
266
  },
226
267
  setFocus(o) {
227
- const c = this.getForm(o);
228
- c && c.focus && c.focus();
268
+ const a = this.getForm(o);
269
+ a && a.focus && a.focus();
229
270
  },
230
- setValue(o, c) {
231
- const u = this.getForm(o);
232
- u && u.value !== c && this.onChange(o, c);
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 T(n, i);
276
+ return q(n, i);
236
277
  },
237
278
  async handleSubmit() {
238
- if (f)
279
+ if (u)
239
280
  return;
240
- l.isSubmitted = !0;
241
- let o = !1, c = !1;
242
- for (const u in i) {
243
- const a = i[u];
244
- if (a.value !== void 0) {
245
- const g = a.validate(a.value);
246
- g && (c = !0, a.error = g, a.rerender(), !o && a.focus && (a.focus(), o = !0));
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
- if (!c) {
250
- if (l.dirtyCount === 0 && t) {
289
+ }), !a) {
290
+ if (f.dirtyCount === 0 && t) {
251
291
  t();
252
292
  return;
253
293
  }
254
- if (!v.onSubmit)
294
+ if (!x.onSubmit)
255
295
  return;
256
- const u = T(n, i);
257
- await v.onSubmit(u, {
258
- setError: (a, g) => {
259
- const F = this.getForm(a);
260
- F.error = {
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
- }, F.rerender();
303
+ }, V.rerender();
264
304
  }
265
- }).catch((a) => {
266
- console.log("[formkit] submit exception:", a);
305
+ }).catch((l) => {
306
+ console.log("[formkit] submit exception:", l);
267
307
  });
268
308
  }
269
309
  },
270
- reset(o, { asDirty: c }) {
271
- S(n, [], o, (u, a, g) => {
272
- if (g === void 0 && i[a].value === void 0)
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 (V.names[a] && g === void 0) {
275
- i[a].value = void 0;
314
+ if (E.names[l] && g === void 0) {
315
+ i[l].value = void 0;
276
316
  return;
277
317
  }
278
- const F = g ?? u.defaultValue;
279
- c || (i[a].startValue = F, i[a].isDirty = !1), i[a].value !== F && this.onChange(a, F);
280
- }), c || (l.dirtyCount = 0, l.isSubmitted = !1), V.subscribers.forEach(({ visualizeEvalueatedForms: u }) => {
281
- u();
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
- S(n, [], {}, (o, c) => {
286
- i[c].startValue = i[c].value, i[c].isDirty = !1;
287
- }), l.dirtyCount = 0, l.isSubmitted = !1;
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, c) {
290
- return i[o].rerender = c, i[o].value === void 0 && (i[o].value = i[o].defaultValue), {
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, l.isActive) {
294
- i[o].value = void 0;
295
- const u = !M(i[o].startValue, i[o].defaultValue);
296
- i[o].isDirty !== u && B(o, u), i[o].isDirty = u;
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, c) {
305
- const u = { callback: c }, a = this.getForm(o);
306
- return a.subscribers.push(u), () => {
307
- a.subscribers = a.subscribers.filter((g) => g !== u);
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 x.add(o), () => {
312
- x.delete(o);
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, c) {
319
- const u = { visualizeEvalueatedForms: c };
320
- return o.forEach((a) => {
321
- V.names[a] = !0;
322
- }), V.subscribers.push(u), {
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
- V.subscribers = V.subscribers.filter((a) => a !== u);
364
+ E.subscribers = E.subscribers.filter((l) => l !== c);
325
365
  }
326
366
  };
327
367
  },
328
- onChange(o, c) {
329
- const u = this.getForm(o), a = !M(c, u.startValue);
330
- u.isDirty !== a && B(o, a), u.isDirty = a, d?.({ name: o, value: c }), (u.error || l.isSubmitted) && (u.error = u.validate(c) || null);
331
- const g = u.value;
332
- u.value = c, u.rerender(), u.subscribers.forEach(({ callback: F }) => {
333
- F(c, g);
334
- }), x.forEach((F) => {
335
- F();
336
- }), D.onChange?.(T(n, i));
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
- }, Y = (n, r) => {
340
- const e = U(null);
341
- e.current === null && (e.current = H(n, r));
342
- const s = e.current;
343
- return $(() => {
344
- e.current && (e.current.submitRef.onSubmit = r.onSubmit, e.current.changeRef.onChange = r.onChange);
345
- }, [r.onSubmit, r.onChange]), {
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) => N(t),
348
- reset: (t, f = {}) => {
349
- s.reset(t, f);
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, f) => {
358
- s.setError(t, f);
397
+ setError: (t, u) => {
398
+ s.setError(t, u);
359
399
  },
360
- setValue: (t, f) => {
361
- s.setValue(t, f);
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, f) => s.subscribeToForm(t, f),
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
- }, Z = ({ manager: n }) => (p(() => {
415
+ }, er = ({ manager: n }) => ($(() => {
376
416
  n.activate();
377
- }, []), $(() => () => {
417
+ }, []), D(() => () => {
378
418
  n.disactivate();
379
- }, []), /* @__PURE__ */ b(A.Provider, { value: n, children: /* @__PURE__ */ b(C, { scheme: n.scheme, path: [] }) })), w = (n) => {
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 (r) {
383
- return r && typeof r == "string" ? {
422
+ } catch (e) {
423
+ return e && typeof e == "string" ? {
384
424
  error: !0,
385
- messages: [r]
386
- } : r instanceof Array && r.every((e) => e && typeof e == "string") ? {
425
+ messages: [e]
426
+ } : e instanceof Array && e.every((r) => r && typeof r == "string") ? {
387
427
  error: !0,
388
- messages: r
428
+ messages: e
389
429
  } : {
390
430
  error: !0
391
431
  };
392
432
  }
393
- }, k = (n) => (r, e) => {
394
- const s = n.getRequireCheck(e), { $rules: t = {}, ...f } = e, { validate: y, required: m } = t;
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: r,
437
+ name: e,
398
438
  defaultValue: n.defaultValue,
399
- Form: n.getForm(f),
400
- validate: (d) => {
401
- if (m) {
402
- const h = w(() => s(d));
403
- if (h)
404
- return h;
405
- if (y) {
406
- const v = w(() => y(d));
407
- if (v)
408
- return v;
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 (y && !w(() => s(d))) {
413
- const v = w(() => y(d));
414
- if (v)
415
- return v;
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
- }, I = (n) => (r) => (...e) => ({
459
+ }, nr = (n) => (e) => (...r) => ({
420
460
  type: "layout",
421
- Layout: n(r),
422
- childs: e
423
- }), rr = ({
461
+ Layout: n(e),
462
+ childs: r
463
+ }), sr = ({
424
464
  getItems: n,
425
- getController: r
465
+ getController: e
426
466
  }) => ({
427
467
  type: "extra",
428
- items: n((e) => (s) => ({ type: "registry", name: e, getForm: s })),
429
- getController: r
430
- }), er = (n) => (...r) => ({
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
- }), tr = (n, r) => (...e) => ({
480
+ }), ur = (n, e) => (...r) => ({
435
481
  type: "condition",
436
482
  depended: n,
437
- canActivate: r.canActivate,
438
- childs: e
439
- }), sr = ({ hidden: n }) => (...r) => ({
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: r
489
+ childs: e
443
490
  });
444
491
  export {
445
- tr as Condition,
446
- er as Context,
447
- Z as FormLayout,
448
- sr as Visablility,
449
- rr as createExtraForm,
450
- k as createForm,
451
- I as createLayout,
452
- X as createUseValue,
453
- Y as useForm,
454
- W as useSetValue,
455
- N as useValue
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
- export declare const Context: <N extends string>(context: N) => <T extends SchemeItems.All[]>(...childs: T) => SchemeItems.Context<N, T>;
3
- export declare const Condition: (depended: string, props: {
2
+ interface ConditionProps {
4
3
  canActivate: (value: any) => boolean;
5
- }) => <T extends SchemeItems.All[]>(...childs: T) => SchemeItems.Condition<T>;
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 {};
@@ -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;
@@ -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
- export { readScheme };
7
+ declare const readShown: (scheme: SchemeItems.All[], path: string[], forms: Forms, callback: shownCb) => void;
8
+ export { readScheme, readShown };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@companix/formkit",
3
- "version": "0.0.29",
3
+ "version": "0.0.31",
4
4
  "module": "./dist/bundle.es.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",
@@ -1,7 +0,0 @@
1
- interface Props {
2
- name: string;
3
- canActivate: (value: any) => boolean;
4
- children: React.ReactNode;
5
- }
6
- export declare const Condition: ({ canActivate, name, children }: Props) => import("react/jsx-runtime").JSX.Element | null;
7
- export {};