@companix/formkit 0.0.28 → 0.0.30

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