@reformer/core 1.1.0 → 2.0.0-beta.10

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.
Files changed (221) hide show
  1. package/dist/behaviors/compute-from.d.ts +2 -0
  2. package/dist/behaviors/compute-from.js +31 -0
  3. package/dist/behaviors/copy-from.d.ts +2 -0
  4. package/dist/behaviors/copy-from.js +29 -0
  5. package/dist/behaviors/enable-when.d.ts +2 -0
  6. package/dist/behaviors/enable-when.js +25 -0
  7. package/dist/behaviors/reset-when.d.ts +2 -0
  8. package/dist/behaviors/reset-when.js +24 -0
  9. package/dist/behaviors/revalidate-when.d.ts +2 -0
  10. package/dist/behaviors/revalidate-when.js +18 -0
  11. package/dist/behaviors/sync-fields.d.ts +2 -0
  12. package/dist/behaviors/sync-fields.js +41 -0
  13. package/dist/behaviors/transform-value.d.ts +2 -0
  14. package/dist/behaviors/transform-value.js +45 -0
  15. package/dist/behaviors/watch-field.d.ts +2 -0
  16. package/dist/behaviors/watch-field.js +21 -0
  17. package/dist/behaviors.d.ts +6 -2
  18. package/dist/behaviors.js +27 -228
  19. package/dist/core/behavior/behavior-context.d.ts +32 -14
  20. package/dist/core/behavior/behavior-registry.d.ts +15 -27
  21. package/dist/core/behavior/behaviors/compute-from.d.ts +50 -21
  22. package/dist/core/behavior/behaviors/copy-from.d.ts +39 -14
  23. package/dist/core/behavior/behaviors/enable-when.d.ts +88 -19
  24. package/dist/core/behavior/behaviors/reset-when.d.ts +31 -18
  25. package/dist/core/behavior/behaviors/revalidate-when.d.ts +40 -17
  26. package/dist/core/behavior/behaviors/sync-fields.d.ts +34 -14
  27. package/dist/core/behavior/behaviors/transform-value.d.ts +116 -44
  28. package/dist/core/behavior/behaviors/watch-field.d.ts +66 -21
  29. package/dist/core/behavior/compose-behavior.d.ts +2 -12
  30. package/dist/core/behavior/index.d.ts +0 -1
  31. package/dist/core/behavior/types.d.ts +2 -8
  32. package/dist/core/factories/node-factory.d.ts +6 -29
  33. package/dist/core/nodes/array-node.d.ts +42 -22
  34. package/dist/core/nodes/field-node.d.ts +51 -26
  35. package/dist/core/nodes/form-node.d.ts +18 -20
  36. package/dist/core/nodes/group-node.d.ts +37 -212
  37. package/dist/core/types/deep-schema.d.ts +2 -12
  38. package/dist/core/types/field-path.d.ts +1 -1
  39. package/dist/core/types/form-context.d.ts +36 -30
  40. package/dist/core/types/{group-node-proxy.d.ts → form-proxy.d.ts} +12 -42
  41. package/dist/core/types/index.d.ts +52 -6
  42. package/dist/core/types/validation-schema.d.ts +3 -12
  43. package/dist/core/utils/abstract-registry.d.ts +74 -0
  44. package/dist/core/utils/aggregate-signals.d.ts +71 -0
  45. package/dist/core/utils/create-form.d.ts +3 -20
  46. package/dist/core/utils/error-handler.d.ts +1 -18
  47. package/dist/core/utils/field-path-navigator.d.ts +1 -1
  48. package/dist/core/{validation → utils}/field-path.d.ts +23 -6
  49. package/dist/core/utils/form-observer.d.ts +176 -0
  50. package/dist/core/utils/form-proxy-builder.d.ts +25 -0
  51. package/dist/core/utils/form-submitter.d.ts +121 -0
  52. package/dist/core/utils/index.d.ts +10 -2
  53. package/dist/core/utils/registry-helpers.d.ts +0 -7
  54. package/dist/core/utils/safe-effect.d.ts +73 -0
  55. package/dist/core/utils/status-machine.d.ts +153 -0
  56. package/dist/core/utils/type-guards.d.ts +5 -23
  57. package/dist/core/utils/unique-id.d.ts +53 -0
  58. package/dist/core/validation/core/apply-when.d.ts +3 -9
  59. package/dist/core/validation/core/apply.d.ts +2 -13
  60. package/dist/core/validation/core/validate-async.d.ts +2 -8
  61. package/dist/core/validation/core/validate-tree.d.ts +10 -10
  62. package/dist/core/validation/core/validate.d.ts +1 -7
  63. package/dist/core/validation/index.d.ts +8 -2
  64. package/dist/core/validation/validate-form.d.ts +1 -38
  65. package/dist/core/validation/validation-applicator.d.ts +2 -21
  66. package/dist/core/validation/validation-context.d.ts +67 -28
  67. package/dist/core/validation/validation-registry.d.ts +11 -25
  68. package/dist/core/validation/validators/array-validators.d.ts +2 -12
  69. package/dist/core/validation/validators/date-utils.d.ts +26 -0
  70. package/dist/core/validation/validators/email.d.ts +2 -9
  71. package/dist/core/validation/validators/future-date.d.ts +35 -0
  72. package/dist/core/validation/validators/index.d.ts +7 -1
  73. package/dist/core/validation/validators/is-date.d.ts +36 -0
  74. package/dist/core/validation/validators/max-age.d.ts +36 -0
  75. package/dist/core/validation/validators/max-date.d.ts +36 -0
  76. package/dist/core/validation/validators/max-length.d.ts +3 -10
  77. package/dist/core/validation/validators/max.d.ts +3 -10
  78. package/dist/core/validation/validators/min-age.d.ts +36 -0
  79. package/dist/core/validation/validators/min-date.d.ts +36 -0
  80. package/dist/core/validation/validators/min-length.d.ts +3 -10
  81. package/dist/core/validation/validators/min.d.ts +3 -10
  82. package/dist/core/validation/validators/number.d.ts +2 -9
  83. package/dist/core/validation/validators/past-date.d.ts +35 -0
  84. package/dist/core/validation/validators/pattern.d.ts +2 -9
  85. package/dist/core/validation/validators/phone.d.ts +2 -9
  86. package/dist/core/validation/validators/required.d.ts +2 -9
  87. package/dist/core/validation/validators/url.d.ts +2 -9
  88. package/dist/date-utils-xUWFslTj.js +29 -0
  89. package/dist/field-path-DuKdGcIE.js +66 -0
  90. package/dist/hooks/types.d.ts +328 -0
  91. package/dist/hooks/useArrayLength.d.ts +31 -0
  92. package/dist/hooks/useFormControl.d.ts +15 -39
  93. package/dist/hooks/useFormControlValue.d.ts +167 -0
  94. package/dist/hooks/useHiddenCondition.d.ts +25 -0
  95. package/dist/hooks/useSignalSubscription.d.ts +17 -0
  96. package/dist/index-D25LsbRm.js +73 -0
  97. package/dist/index.d.ts +8 -1
  98. package/dist/index.js +3271 -8
  99. package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
  100. package/dist/safe-effect-Dh8uw81c.js +20 -0
  101. package/dist/validate-C3XiA_zf.js +10 -0
  102. package/dist/validators/email.d.ts +2 -0
  103. package/dist/validators/email.js +13 -0
  104. package/dist/validators/future-date.d.ts +2 -0
  105. package/dist/validators/future-date.js +20 -0
  106. package/dist/validators/is-date.d.ts +2 -0
  107. package/dist/validators/is-date.js +12 -0
  108. package/dist/validators/max-age.d.ts +2 -0
  109. package/dist/validators/max-age.js +20 -0
  110. package/dist/validators/max-date.d.ts +2 -0
  111. package/dist/validators/max-date.js +20 -0
  112. package/dist/validators/max-length.d.ts +2 -0
  113. package/dist/validators/max-length.js +11 -0
  114. package/dist/validators/max.d.ts +2 -0
  115. package/dist/validators/max.js +11 -0
  116. package/dist/validators/min-age.d.ts +2 -0
  117. package/dist/validators/min-age.js +20 -0
  118. package/dist/validators/min-date.d.ts +2 -0
  119. package/dist/validators/min-date.js +20 -0
  120. package/dist/validators/min-length.d.ts +2 -0
  121. package/dist/validators/min-length.js +11 -0
  122. package/dist/validators/min.d.ts +2 -0
  123. package/dist/validators/min.js +11 -0
  124. package/dist/validators/number.d.ts +2 -0
  125. package/dist/validators/number.js +35 -0
  126. package/dist/validators/past-date.d.ts +2 -0
  127. package/dist/validators/past-date.js +20 -0
  128. package/dist/validators/pattern.d.ts +2 -0
  129. package/dist/validators/pattern.js +11 -0
  130. package/dist/validators/phone.d.ts +2 -0
  131. package/dist/validators/phone.js +35 -0
  132. package/dist/validators/required.d.ts +2 -0
  133. package/dist/validators/required.js +15 -0
  134. package/dist/validators/url.d.ts +2 -0
  135. package/dist/validators/url.js +19 -0
  136. package/dist/validators-BGsNOgT1.js +207 -0
  137. package/dist/validators.d.ts +6 -2
  138. package/dist/validators.js +54 -296
  139. package/llms.txt +8887 -59
  140. package/package.json +87 -8
  141. package/dist/core/behavior/behavior-applicator.d.ts +0 -71
  142. package/dist/core/behavior/behavior-applicator.js +0 -92
  143. package/dist/core/behavior/behavior-context.js +0 -38
  144. package/dist/core/behavior/behavior-registry.js +0 -198
  145. package/dist/core/behavior/behaviors/compute-from.js +0 -84
  146. package/dist/core/behavior/behaviors/copy-from.js +0 -64
  147. package/dist/core/behavior/behaviors/enable-when.js +0 -81
  148. package/dist/core/behavior/behaviors/index.js +0 -11
  149. package/dist/core/behavior/behaviors/reset-when.js +0 -63
  150. package/dist/core/behavior/behaviors/revalidate-when.js +0 -51
  151. package/dist/core/behavior/behaviors/sync-fields.js +0 -66
  152. package/dist/core/behavior/behaviors/transform-value.js +0 -110
  153. package/dist/core/behavior/behaviors/watch-field.js +0 -56
  154. package/dist/core/behavior/compose-behavior.js +0 -166
  155. package/dist/core/behavior/create-field-path.d.ts +0 -20
  156. package/dist/core/behavior/create-field-path.js +0 -69
  157. package/dist/core/behavior/index.js +0 -17
  158. package/dist/core/behavior/types.js +0 -7
  159. package/dist/core/context/form-context-impl.d.ts +0 -29
  160. package/dist/core/context/form-context-impl.js +0 -37
  161. package/dist/core/factories/index.js +0 -6
  162. package/dist/core/factories/node-factory.js +0 -281
  163. package/dist/core/nodes/array-node.js +0 -534
  164. package/dist/core/nodes/field-node.js +0 -510
  165. package/dist/core/nodes/form-node.js +0 -343
  166. package/dist/core/nodes/group-node/field-registry.d.ts +0 -191
  167. package/dist/core/nodes/group-node/field-registry.js +0 -215
  168. package/dist/core/nodes/group-node/index.d.ts +0 -11
  169. package/dist/core/nodes/group-node/index.js +0 -11
  170. package/dist/core/nodes/group-node/proxy-builder.d.ts +0 -71
  171. package/dist/core/nodes/group-node/proxy-builder.js +0 -161
  172. package/dist/core/nodes/group-node/state-manager.d.ts +0 -184
  173. package/dist/core/nodes/group-node/state-manager.js +0 -265
  174. package/dist/core/nodes/group-node.js +0 -770
  175. package/dist/core/types/deep-schema.js +0 -11
  176. package/dist/core/types/field-path.js +0 -4
  177. package/dist/core/types/form-context.js +0 -25
  178. package/dist/core/types/group-node-proxy.js +0 -31
  179. package/dist/core/types/index.js +0 -4
  180. package/dist/core/types/validation-schema.js +0 -10
  181. package/dist/core/utils/create-form.js +0 -24
  182. package/dist/core/utils/debounce.d.ts +0 -160
  183. package/dist/core/utils/debounce.js +0 -197
  184. package/dist/core/utils/error-handler.js +0 -226
  185. package/dist/core/utils/field-path-navigator.js +0 -374
  186. package/dist/core/utils/index.js +0 -14
  187. package/dist/core/utils/registry-helpers.js +0 -79
  188. package/dist/core/utils/registry-stack.js +0 -86
  189. package/dist/core/utils/resources.d.ts +0 -41
  190. package/dist/core/utils/resources.js +0 -69
  191. package/dist/core/utils/subscription-manager.js +0 -214
  192. package/dist/core/utils/type-guards.js +0 -169
  193. package/dist/core/validation/core/apply-when.js +0 -41
  194. package/dist/core/validation/core/apply.js +0 -38
  195. package/dist/core/validation/core/index.js +0 -8
  196. package/dist/core/validation/core/validate-async.js +0 -45
  197. package/dist/core/validation/core/validate-tree.js +0 -37
  198. package/dist/core/validation/core/validate.js +0 -38
  199. package/dist/core/validation/field-path.js +0 -147
  200. package/dist/core/validation/index.js +0 -33
  201. package/dist/core/validation/validate-form.js +0 -152
  202. package/dist/core/validation/validation-applicator.js +0 -217
  203. package/dist/core/validation/validation-context.js +0 -75
  204. package/dist/core/validation/validation-registry.js +0 -298
  205. package/dist/core/validation/validators/array-validators.js +0 -86
  206. package/dist/core/validation/validators/date.d.ts +0 -38
  207. package/dist/core/validation/validators/date.js +0 -117
  208. package/dist/core/validation/validators/email.js +0 -60
  209. package/dist/core/validation/validators/index.js +0 -14
  210. package/dist/core/validation/validators/max-length.js +0 -60
  211. package/dist/core/validation/validators/max.js +0 -60
  212. package/dist/core/validation/validators/min-length.js +0 -60
  213. package/dist/core/validation/validators/min.js +0 -60
  214. package/dist/core/validation/validators/number.js +0 -90
  215. package/dist/core/validation/validators/pattern.js +0 -62
  216. package/dist/core/validation/validators/phone.js +0 -58
  217. package/dist/core/validation/validators/required.js +0 -69
  218. package/dist/core/validation/validators/url.js +0 -55
  219. package/dist/create-field-path-CdPF3lIK.js +0 -704
  220. package/dist/hooks/useFormControl.js +0 -298
  221. package/dist/node-factory-D7DOnSSN.js +0 -3200
@@ -1,81 +0,0 @@
1
- /**
2
- * Условное включение/отключение полей
3
- *
4
- * @group Behaviors
5
- * @category Behavior Rules
6
- * @module behaviors/enableWhen
7
- */
8
- import { effect } from '@preact/signals-core';
9
- import { getCurrentBehaviorRegistry } from '../../utils/registry-helpers';
10
- /**
11
- * Условное включение поля на основе значений других полей
12
- *
13
- * @group Behaviors
14
- * @category Behavior Rules
15
- *
16
- * @param field - Поле для включения/выключения
17
- * @param condition - Функция условия (true = enable, false = disable)
18
- * @param options - Опции
19
- *
20
- * @example
21
- * ```typescript
22
- * const schema: BehaviorSchemaFn<MyForm> = (path) => {
23
- * // Включить поле только для ипотеки
24
- * enableWhen(path.propertyValue, (form) => form.loanType === 'mortgage', {
25
- * resetOnDisable: true
26
- * });
27
- * };
28
- * ```
29
- */
30
- export function enableWhen(
31
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
- field, condition, options) {
33
- const { debounce, resetOnDisable = false } = options || {};
34
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
- const handler = (form, _context, withDebounce) => {
36
- const targetNode = form.getFieldByPath(field.__path);
37
- if (!targetNode)
38
- return null;
39
- return effect(() => {
40
- const formValue = form.value.value;
41
- withDebounce(() => {
42
- const shouldEnable = condition(formValue);
43
- if (shouldEnable) {
44
- targetNode.enable();
45
- }
46
- else {
47
- targetNode.disable();
48
- if (resetOnDisable) {
49
- targetNode.reset();
50
- }
51
- }
52
- });
53
- });
54
- };
55
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
- getCurrentBehaviorRegistry().register(handler, { debounce });
57
- }
58
- /**
59
- * Условное выключение поля (инверсия enableWhen)
60
- *
61
- * @group Behaviors
62
- * @category Behavior Rules
63
- *
64
- * @param field - Поле для выключения
65
- * @param condition - Функция условия (true = disable, false = enable)
66
- * @param options - Опции
67
- *
68
- * @example
69
- * ```typescript
70
- * const schema: BehaviorSchemaFn<MyForm> = (path) => {
71
- * // Выключить поле для потребительского кредита
72
- * disableWhen(path.propertyValue, (form) => form.loanType === 'consumer');
73
- * };
74
- * ```
75
- */
76
- export function disableWhen(
77
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
- field, condition, options) {
79
- // Инвертируем условие
80
- enableWhen(field, (form) => !condition(form), options);
81
- }
@@ -1,11 +0,0 @@
1
- /**
2
- * Behavior rules
3
- */
4
- export { copyFrom } from './copy-from';
5
- export { enableWhen, disableWhen } from './enable-when';
6
- export { computeFrom } from './compute-from';
7
- export { watchField } from './watch-field';
8
- export { revalidateWhen } from './revalidate-when';
9
- export { syncFields } from './sync-fields';
10
- export { resetWhen } from './reset-when';
11
- export { transformValue, createTransformer, transformers, } from './transform-value';
@@ -1,63 +0,0 @@
1
- /**
2
- * Условный сброс полей
3
- *
4
- * @group Behaviors
5
- * @category Behavior Rules
6
- * @module behaviors/resetWhen
7
- */
8
- import { effect } from '@preact/signals-core';
9
- import { getCurrentBehaviorRegistry } from '../../utils/registry-helpers';
10
- /**
11
- * Условный сброс поля при выполнении условия
12
- *
13
- * @group Behaviors
14
- * @category Behavior Rules
15
- *
16
- * @param field - Поле для сброса
17
- * @param condition - Функция условия (true = reset)
18
- * @param options - Опции
19
- *
20
- * @example
21
- * ```typescript
22
- * const schema: BehaviorSchemaFn<MyForm> = (path) => {
23
- * // Сбросить поле при изменении типа кредита
24
- * resetWhen(path.propertyValue, (form) => form.loanType !== 'mortgage');
25
- *
26
- * // Сбросить с кастомным значением
27
- * resetWhen(path.initialPayment, (form) => !form.propertyValue, {
28
- * resetValue: 0
29
- * });
30
- *
31
- * // Сбросить только если поле было изменено пользователем
32
- * resetWhen(path.carPrice, (form) => form.loanType !== 'car', {
33
- * onlyIfDirty: true
34
- * });
35
- * };
36
- * ```
37
- */
38
- export function resetWhen(field, condition, options) {
39
- const { debounce, resetValue = null, onlyIfDirty = false } = options || {};
40
- const handler = (form, _context, withDebounce) => {
41
- const targetNode = form.getFieldByPath(field.__path);
42
- if (!targetNode)
43
- return null;
44
- return effect(() => {
45
- const formValue = form.value.value;
46
- withDebounce(() => {
47
- const shouldReset = condition(formValue);
48
- if (shouldReset) {
49
- // Проверяем onlyIfDirty опцию
50
- if (onlyIfDirty && !targetNode.dirty.value) {
51
- return;
52
- }
53
- // Сбрасываем значение
54
- targetNode.setValue(resetValue);
55
- // Сбрасываем флаги dirty и touched
56
- targetNode.markAsPristine();
57
- targetNode.markAsUntouched();
58
- }
59
- });
60
- });
61
- };
62
- getCurrentBehaviorRegistry().register(handler, { debounce });
63
- }
@@ -1,51 +0,0 @@
1
- /**
2
- * Перевалидация полей при изменениях
3
- *
4
- * @group Behaviors
5
- * @category Behavior Rules
6
- * @module behaviors/revalidateWhen
7
- */
8
- import { effect } from '@preact/signals-core';
9
- import { getCurrentBehaviorRegistry } from '../../utils/registry-helpers';
10
- /**
11
- * Перевалидирует поле при изменении других полей
12
- *
13
- * @group Behaviors
14
- * @category Behavior Rules
15
- *
16
- * @param target - Поле для перевалидации
17
- * @param triggers - Поля-триггеры
18
- * @param options - Опции
19
- *
20
- * @example
21
- * ```typescript
22
- * const schema: BehaviorSchemaFn<MyForm> = (path) => {
23
- * // Перевалидировать initialPayment при изменении propertyValue
24
- * revalidateWhen(path.initialPayment, [path.propertyValue], {
25
- * debounce: 300
26
- * });
27
- * };
28
- * ```
29
- */
30
- export function revalidateWhen(target, triggers, options) {
31
- const { debounce } = options || {};
32
- const handler = (form, _context, withDebounce) => {
33
- const targetNode = form.getFieldByPath(target.__path);
34
- if (!targetNode)
35
- return null;
36
- const sourceNodes = triggers
37
- .map((field) => form.getFieldByPath(field.__path))
38
- .filter((node) => node !== undefined);
39
- if (sourceNodes.length === 0)
40
- return null;
41
- return effect(() => {
42
- // Отслеживаем изменения source полей
43
- sourceNodes.forEach((node) => node.value.value);
44
- withDebounce(() => {
45
- // Перезапускаем валидацию target поля
46
- targetNode.validate();
47
- });
48
- });
49
- };
50
- getCurrentBehaviorRegistry().register(handler, { debounce });
51
- }
@@ -1,66 +0,0 @@
1
- /**
2
- * Двусторонняя синхронизация полей
3
- *
4
- * @group Behaviors
5
- * @category Behavior Rules
6
- * @module behaviors/syncFields
7
- */
8
- import { effect } from '@preact/signals-core';
9
- import { getCurrentBehaviorRegistry } from '../../utils/registry-helpers';
10
- /**
11
- * Двусторонняя синхронизация двух полей
12
- *
13
- * @group Behaviors
14
- * @category Behavior Rules
15
- *
16
- * @param field1 - Первое поле
17
- * @param field2 - Второе поле
18
- * @param options - Опции
19
- *
20
- * @example
21
- * ```typescript
22
- * const schema: BehaviorSchemaFn<MyForm> = (path) => {
23
- * // Синхронизировать два поля
24
- * syncFields(path.email, path.emailCopy);
25
- * };
26
- * ```
27
- */
28
- export function syncFields(field1, field2, options) {
29
- const { debounce, transform } = options || {};
30
- const handler = (form, _context, withDebounce) => {
31
- const sourceNode = form.getFieldByPath(field1.__path);
32
- const targetNode = form.getFieldByPath(field2.__path);
33
- if (!sourceNode || !targetNode)
34
- return null;
35
- // Флаг для предотвращения циклических обновлений
36
- let isUpdating = false;
37
- const dispose1 = effect(() => {
38
- const sourceValue = sourceNode.value.value;
39
- if (isUpdating)
40
- return;
41
- withDebounce(() => {
42
- isUpdating = true;
43
- const finalValue = transform ? transform(sourceValue) : sourceValue;
44
- targetNode.setValue(finalValue, { emitEvent: false });
45
- isUpdating = false;
46
- });
47
- });
48
- const dispose2 = effect(() => {
49
- const targetValue = targetNode.value.value;
50
- if (isUpdating)
51
- return;
52
- withDebounce(() => {
53
- isUpdating = true;
54
- // Обратная синхронизация (без трансформации)
55
- sourceNode.setValue(targetValue, { emitEvent: false });
56
- isUpdating = false;
57
- });
58
- });
59
- // Возвращаем комбинированный cleanup
60
- return () => {
61
- dispose1();
62
- dispose2();
63
- };
64
- };
65
- getCurrentBehaviorRegistry().register(handler, { debounce });
66
- }
@@ -1,110 +0,0 @@
1
- /**
2
- * Трансформация значений полей
3
- *
4
- * @group Behaviors
5
- * @category Behavior Rules
6
- * @module behaviors/transformValue
7
- */
8
- import { watchField } from './watch-field';
9
- /**
10
- * Трансформация значения поля при изменении
11
- * Позволяет автоматически форматировать или преобразовывать значения
12
- *
13
- * @group Behaviors
14
- * @category Behavior Rules
15
- *
16
- * @param field - Поле для трансформации
17
- * @param transformer - Функция трансформации
18
- * @param options - Опции
19
- *
20
- * @example
21
- * ```typescript
22
- * const schema: BehaviorSchemaFn<MyForm> = (path) => {
23
- * // Автоматически переводить текст в верхний регистр
24
- * transformValue(path.code, (value) => value?.toUpperCase());
25
- *
26
- * // Форматировать номер телефона
27
- * transformValue(path.phone, (value) => {
28
- * if (!value) return value;
29
- * const digits = value.replace(/\D/g, '');
30
- * if (digits.length === 11) {
31
- * return `+7 (${digits.slice(1, 4)}) ${digits.slice(4, 7)}-${digits.slice(7, 9)}-${digits.slice(9)}`;
32
- * }
33
- * return value;
34
- * });
35
- *
36
- * // Удалять пробелы из email
37
- * transformValue(path.email, (value) => value?.trim().toLowerCase());
38
- *
39
- * // Округлять числа
40
- * transformValue(path.amount, (value) => {
41
- * return typeof value === 'number' ? Math.round(value) : value;
42
- * });
43
- * };
44
- * ```
45
- */
46
- export function transformValue(field, transformer, options) {
47
- const { onUserChangeOnly = false, emitEvent = true, debounce } = options || {};
48
- watchField(field, (currentValue, ctx) => {
49
- const targetNode = ctx.form.getFieldByPath(field.__path);
50
- if (!targetNode)
51
- return;
52
- // Если нужно трансформировать только при изменении пользователем
53
- if (onUserChangeOnly && !targetNode.touched.value) {
54
- return;
55
- }
56
- const transformedValue = transformer(currentValue);
57
- // Применяем трансформацию только если значение изменилось
58
- if (transformedValue !== currentValue) {
59
- targetNode.setValue(transformedValue, { emitEvent });
60
- }
61
- }, { debounce });
62
- }
63
- /**
64
- * Хелпер для создания переиспользуемых трансформаций
65
- *
66
- * @group Behaviors
67
- * @category Behavior Rules
68
- *
69
- * @example
70
- * ```typescript
71
- * // Создаем переиспользуемые трансформеры
72
- * const toUpperCase = createTransformer<string>((value) => value?.toUpperCase());
73
- * const toLowerCase = createTransformer<string>((value) => value?.toLowerCase());
74
- * const trim = createTransformer<string>((value) => value?.trim());
75
- *
76
- * // Используем в форме
77
- * const schema: BehaviorSchemaFn<MyForm> = (path) => {
78
- * toUpperCase(path.code);
79
- * toLowerCase(path.email);
80
- * trim(path.username);
81
- * };
82
- * ```
83
- */
84
- export function createTransformer(transformer, defaultOptions) {
85
- return (field, options) => {
86
- transformValue(field, transformer, { ...defaultOptions, ...options });
87
- };
88
- }
89
- /**
90
- * Готовые трансформеры для частых случаев
91
- *
92
- * @group Behaviors
93
- * @category Behavior Rules
94
- */
95
- export const transformers = {
96
- /** Перевести в верхний регистр */
97
- toUpperCase: createTransformer((value) => value?.toUpperCase()),
98
- /** Перевести в нижний регистр */
99
- toLowerCase: createTransformer((value) => value?.toLowerCase()),
100
- /** Удалить пробелы с краев */
101
- trim: createTransformer((value) => value?.trim()),
102
- /** Удалить все пробелы */
103
- removeSpaces: createTransformer((value) => value?.replace(/\s/g, '')),
104
- /** Оставить только цифры */
105
- digitsOnly: createTransformer((value) => value?.replace(/\D/g, '')),
106
- /** Округлить число */
107
- round: createTransformer((value) => typeof value === 'number' ? Math.round(value) : value),
108
- /** Округлить до 2 знаков после запятой */
109
- roundTo2: createTransformer((value) => typeof value === 'number' ? Math.round(value * 100) / 100 : value),
110
- };
@@ -1,56 +0,0 @@
1
- /**
2
- * Отслеживание изменений поля
3
- *
4
- * @group Behaviors
5
- * @category Behavior Rules
6
- * @module behaviors/watchField
7
- */
8
- import { effect } from '@preact/signals-core';
9
- import { getCurrentBehaviorRegistry } from '../../utils/registry-helpers';
10
- /**
11
- * Выполняет callback при изменении поля
12
- *
13
- * @group Behaviors
14
- * @category Behavior Rules
15
- *
16
- * @param field - Поле для отслеживания
17
- * @param callback - Функция обратного вызова
18
- * @param options - Опции
19
- *
20
- * @example
21
- * ```typescript
22
- * const schema: BehaviorSchemaFn<MyForm> = (path) => {
23
- * // Динамическая загрузка городов при изменении страны
24
- * watchField(path.registrationAddress.country, async (country, ctx) => {
25
- * if (country) {
26
- * const cities = await fetchCities(country);
27
- * ctx.updateComponentProps(path.registrationAddress.city, {
28
- * options: cities
29
- * });
30
- * }
31
- * });
32
- * };
33
- * ```
34
- */
35
- export function watchField(field, callback, options) {
36
- const { debounce, immediate = false } = options || {};
37
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
- const handler = (form, context, withDebounce) => {
39
- const node = form.getFieldByPath(field.__path);
40
- if (!node)
41
- return null;
42
- // Вызвать сразу если immediate: true
43
- if (immediate) {
44
- const value = node.value.value;
45
- callback(value, context);
46
- }
47
- return effect(() => {
48
- const value = node.value.value;
49
- withDebounce(() => {
50
- callback(value, context);
51
- });
52
- });
53
- };
54
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
- getCurrentBehaviorRegistry().register(handler, { debounce });
56
- }
@@ -1,166 +0,0 @@
1
- /**
2
- * Композиция behavior схем
3
- *
4
- * Предоставляет функции для переиспользования behavior схем:
5
- * - toBehaviorFieldPath: преобразование FieldPath во вложенный путь
6
- * - apply: применение схемы к полям
7
- * - applyWhen: условное применение схемы
8
- *
9
- * Аналог toFieldPath и applyWhen из validation API.
10
- */
11
- import { createFieldPath } from './create-field-path';
12
- import { watchField } from './behaviors/watch-field';
13
- // ============================================================================
14
- // toBehaviorFieldPath - Преобразование FieldPath во вложенный путь
15
- // ============================================================================
16
- /**
17
- * Преобразовать FieldPath во вложенный путь для композиции behavior схем
18
- *
19
- * Аналог toFieldPath из validation API.
20
- *
21
- * @param fieldPath - Поле для преобразования
22
- * @returns Вложенный FieldPath
23
- *
24
- * @example
25
- * ```typescript
26
- * // address-behavior.ts
27
- * export const addressBehavior = (path: FieldPath<Address>) => {
28
- * watchField(path.country, async (country, ctx) => {
29
- * const regions = await fetchRegions(country);
30
- * ctx.updateComponentProps(path.region, { options: regions });
31
- * });
32
- * };
33
- *
34
- * // user-behavior.ts
35
- * export const userBehavior = (path: FieldPath<User>) => {
36
- * // Композиция: применяем addressBehavior к вложенному полю
37
- * addressBehavior(toBehaviorFieldPath(path.address));
38
- * };
39
- * ```
40
- */
41
- export function toBehaviorFieldPath(fieldPath) {
42
- if (!fieldPath) {
43
- return createFieldPath();
44
- }
45
- const basePath = fieldPath.__path;
46
- return createNestedBehaviorFieldPath(basePath);
47
- }
48
- /**
49
- * Создать вложенный FieldPath с базовым префиксом
50
- * @private
51
- */
52
- function createNestedBehaviorFieldPath(basePath) {
53
- return new Proxy({}, {
54
- get(_target, prop) {
55
- if (typeof prop === 'symbol')
56
- return undefined;
57
- const fullPath = basePath ? `${basePath}.${prop}` : prop;
58
- return {
59
- __path: fullPath,
60
- __key: prop,
61
- };
62
- },
63
- });
64
- }
65
- // ============================================================================
66
- // apply - Применение behavior схемы к полям
67
- // ============================================================================
68
- /**
69
- * Применить behavior схему к вложенному полю или полям
70
- *
71
- * Поддерживает:
72
- * - Одно поле или массив полей
73
- * - Одну схему или массив схем
74
- * - Все комбинации (поле + схема, поле + схемы, поля + схема, поля + схемы)
75
- *
76
- * @param fields - Одно поле или массив полей
77
- * @param behaviors - Одна схема или массив схем
78
- *
79
- * @example
80
- * ```typescript
81
- * // Одна схема к одному полю
82
- * apply(path.registrationAddress, addressBehavior);
83
- *
84
- * // Одна схема к нескольким полям
85
- * apply([path.registrationAddress, path.residenceAddress], addressBehavior);
86
- *
87
- * // Несколько схем к одному полю
88
- * apply(path.properties, [propertyBehavior, arrayBehavior]);
89
- *
90
- * // Несколько схем к нескольким полям
91
- * apply(
92
- * [path.registrationAddress, path.residenceAddress],
93
- * [addressBehavior, validationBehavior]
94
- * );
95
- * ```
96
- */
97
- export function apply(fields, behaviors) {
98
- // Нормализуем inputs в массивы
99
- const fieldArray = (Array.isArray(fields) ? fields : [fields]).filter(Boolean);
100
- const behaviorArray = Array.isArray(behaviors) ? behaviors : [behaviors];
101
- // Применяем все схемы ко всем полям
102
- for (const field of fieldArray) {
103
- const nestedPath = toBehaviorFieldPath(field);
104
- for (const behavior of behaviorArray) {
105
- behavior(nestedPath);
106
- }
107
- }
108
- }
109
- // ============================================================================
110
- // applyWhen - Условное применение behavior схемы
111
- // ============================================================================
112
- /**
113
- * Условное применение behavior схем (аналог applyWhen из validation API)
114
- *
115
- * ⚠️ ВАЖНО: Эта функция НЕ создаёт новые behaviors при каждом изменении условия!
116
- * Вместо этого behaviors регистрируются ОДИН РАЗ при первом вызове и затем
117
- * просто не выполняются, если условие не выполнено.
118
- *
119
- * Это отличается от старой реализации, которая создавала утечку памяти,
120
- * регистрируя behaviors при каждом изменении conditionField.
121
- *
122
- * @param conditionField - Поле для проверки условия
123
- * @param condition - Функция проверки условия
124
- * @param callback - Callback для применения behavior схем
125
- *
126
- * @example
127
- * ```typescript
128
- * // Применить addressBehavior только когда sameAsRegistration === false
129
- * applyWhen(
130
- * path.sameAsRegistration,
131
- * (value) => value === false,
132
- * (path) => {
133
- * apply(path.residenceAddress, addressBehavior);
134
- * }
135
- * );
136
- *
137
- * // Или с прямым использованием path
138
- * applyWhen(
139
- * path.hasProperty,
140
- * (value) => value === true,
141
- * (path) => {
142
- * apply(path.properties, propertyBehavior);
143
- * // Можно применить несколько схем
144
- * apply([path.properties, path.items], arrayBehavior);
145
- * }
146
- * );
147
- * ```
148
- */
149
- export function applyWhen(conditionField, condition, callback) {
150
- if (!conditionField)
151
- return;
152
- // ИСПРАВЛЕНО: Регистрируем behaviors только ОДИН РАЗ
153
- // вне watchField callback, чтобы избежать утечки памяти
154
- let hasRegistered = false;
155
- watchField(conditionField, (value, _ctx) => {
156
- // Регистрируем behaviors только при первом срабатывании
157
- // когда условие выполнено
158
- if (!hasRegistered && condition(value)) {
159
- const fieldPath = createFieldPath();
160
- callback(fieldPath);
161
- hasRegistered = true;
162
- }
163
- // TODO: В будущем можно добавить поддержку деактивации behaviors
164
- // при изменении условия, но это требует изменений в BehaviorRegistry
165
- }, { immediate: true });
166
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * Создание типизированного FieldPath для Behavior Schema
3
- * Аналогично createFieldPath из validators
4
- */
5
- import type { FieldPath } from '../types';
6
- /**
7
- * Создать типизированный путь к полям формы
8
- * Используется для декларативного описания behavior схем
9
- *
10
- * @example
11
- * ```typescript
12
- * const schema: BehaviorSchemaFn<MyForm> = (path) => {
13
- * // path.email, path.address.city и т.д. - типизированы
14
- * copyFrom(path.residenceAddress, path.registrationAddress, {
15
- * when: (form) => form.sameAsRegistration
16
- * });
17
- * };
18
- * ```
19
- */
20
- export declare function createFieldPath<T>(): FieldPath<T>;