@reformer/core 11.0.0-beta.7 → 11.0.0-beta.9

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 (226) hide show
  1. package/README.md +90 -68
  2. package/dist/behaviors-value-HA_Q03hc.js +108 -0
  3. package/dist/behaviors.js +382 -217
  4. package/dist/create-model-BvcbNPgL.js +30 -0
  5. package/dist/date-utils-90-qZbse.js +43 -0
  6. package/dist/{en-CjAqn7h0.js → en-HP8XEych.js} +6 -3
  7. package/dist/form/aggregate-signals.d.ts +21 -63
  8. package/dist/form/behaviors/collections.d.ts +42 -8
  9. package/dist/form/behaviors/context.d.ts +37 -4
  10. package/dist/form/behaviors/index.d.ts +6 -4
  11. package/dist/form/behaviors/internals.d.ts +9 -3
  12. package/dist/form/behaviors/node.d.ts +25 -2
  13. package/dist/form/behaviors/operators.d.ts +17 -9
  14. package/dist/form/behaviors/schema-operators.d.ts +78 -0
  15. package/dist/form/behaviors/types.d.ts +25 -5
  16. package/dist/form/create-form.d.ts +57 -70
  17. package/dist/form/flow/flow.d.ts +87 -0
  18. package/dist/form/form-bundle.d.ts +153 -0
  19. package/dist/form/form-config-base.d.ts +46 -0
  20. package/dist/form/form-level.d.ts +121 -0
  21. package/dist/form/form-proxy-builder.d.ts +6 -22
  22. package/dist/form/index.d.ts +20 -20
  23. package/dist/form/nodes/form-array-node.d.ts +100 -0
  24. package/dist/form/nodes/form-control-node.d.ts +73 -0
  25. package/dist/form/nodes/form-group-node.d.ts +66 -0
  26. package/dist/form/nodes/node-kind.d.ts +29 -0
  27. package/dist/form/nodes/state/availability.d.ts +6 -0
  28. package/dist/form/nodes/state/component.d.ts +6 -0
  29. package/dist/form/nodes/state/index.d.ts +12 -0
  30. package/dist/form/nodes/state/interaction.d.ts +13 -0
  31. package/dist/form/nodes/state/issues.d.ts +9 -0
  32. package/dist/form/nodes/state/pending.d.ts +6 -0
  33. package/dist/form/schema/compile.d.ts +59 -0
  34. package/dist/form/schema/compiled.d.ts +143 -0
  35. package/dist/form/schema/row-key.d.ts +11 -0
  36. package/dist/form/schema-controller.d.ts +153 -0
  37. package/dist/form/schema-subtree.d.ts +28 -0
  38. package/dist/form/signal-node-registry.d.ts +27 -22
  39. package/dist/form/submission.d.ts +93 -0
  40. package/dist/form/type-guards.d.ts +14 -73
  41. package/dist/form/types/contracts.d.ts +19 -92
  42. package/dist/form/types/field-config.d.ts +27 -0
  43. package/dist/form/types/index.d.ts +5 -57
  44. package/dist/form/types/nodes.d.ts +159 -0
  45. package/dist/form/types/schema-node.d.ts +147 -46
  46. package/dist/form/types/validation-schema.d.ts +23 -27
  47. package/dist/form/validation/context.d.ts +46 -6
  48. package/dist/form/validation/index.d.ts +9 -8
  49. package/dist/form/validation/operators.d.ts +71 -17
  50. package/dist/form/validation/run.d.ts +93 -18
  51. package/dist/form/validation/strategy.d.ts +41 -13
  52. package/dist/form/validation/types.d.ts +74 -19
  53. package/dist/form/validators/date-utils.d.ts +13 -1
  54. package/dist/form/validators/email.d.ts +8 -7
  55. package/dist/form/validators/file-type.d.ts +8 -7
  56. package/dist/form/validators/file-utils.d.ts +2 -1
  57. package/dist/form/validators/future-date.d.ts +8 -7
  58. package/dist/form/validators/index.d.ts +1 -1
  59. package/dist/form/validators/integer.d.ts +8 -7
  60. package/dist/form/validators/is-date.d.ts +11 -9
  61. package/dist/form/validators/is-number.d.ts +11 -9
  62. package/dist/form/validators/max-age.d.ts +13 -9
  63. package/dist/form/validators/max-date.d.ts +8 -7
  64. package/dist/form/validators/max-file-size.d.ts +8 -7
  65. package/dist/form/validators/max-files.d.ts +8 -7
  66. package/dist/form/validators/max-length.d.ts +14 -7
  67. package/dist/form/validators/max-total-file-size.d.ts +8 -7
  68. package/dist/form/validators/max.d.ts +10 -8
  69. package/dist/form/validators/min-age.d.ts +12 -9
  70. package/dist/form/validators/min-date.d.ts +8 -7
  71. package/dist/form/validators/min-file-size.d.ts +8 -7
  72. package/dist/form/validators/min-files.d.ts +11 -9
  73. package/dist/form/validators/min-length.d.ts +14 -7
  74. package/dist/form/validators/min.d.ts +10 -8
  75. package/dist/form/validators/multiple-of.d.ts +10 -8
  76. package/dist/form/validators/non-negative.d.ts +8 -7
  77. package/dist/form/validators/non-zero.d.ts +8 -7
  78. package/dist/form/validators/past-date.d.ts +8 -7
  79. package/dist/form/validators/pattern.d.ts +9 -8
  80. package/dist/form/validators/phone.d.ts +8 -7
  81. package/dist/form/validators/required.d.ts +11 -9
  82. package/dist/form/validators/url.d.ts +20 -13
  83. package/dist/form/validators/validation-issue.d.ts +8 -0
  84. package/dist/i18n/descriptor.d.ts +1 -1
  85. package/dist/i18n/en.json.d.ts +5 -1
  86. package/dist/i18n/locale-store.d.ts +7 -0
  87. package/dist/i18n/message-format.d.ts +24 -4
  88. package/dist/i18n/ru.json.d.ts +5 -1
  89. package/dist/i18n/translator.d.ts +11 -0
  90. package/dist/i18n/validation-message.d.ts +42 -7
  91. package/dist/i18n.d.ts +7 -12
  92. package/dist/i18n.js +66 -283
  93. package/dist/index.d.ts +16 -7
  94. package/dist/index.js +958 -2798
  95. package/dist/loader-BWkigpVe.js +52 -0
  96. package/dist/locale/en.js +1 -1
  97. package/dist/locale/en.json +4 -1
  98. package/dist/locale/ru.js +4 -1
  99. package/dist/locale/ru.json +4 -1
  100. package/dist/locale-CG54AU2Q.js +219 -0
  101. package/dist/locale.js +1 -1
  102. package/dist/model/behaviors-value.d.ts +24 -6
  103. package/dist/model/create-model.d.ts +2 -2
  104. package/dist/model/derived-registry.d.ts +1 -1
  105. package/dist/model/index.d.ts +16 -5
  106. package/dist/model/model-nodes.d.ts +138 -8
  107. package/dist/model/model-signals-proxy.d.ts +11 -5
  108. package/dist/model/model-value-proxy.d.ts +84 -3
  109. package/dist/model/safe-effect.d.ts +33 -1
  110. package/dist/model/types.d.ts +70 -17
  111. package/dist/model.js +21 -17
  112. package/dist/node-kind-C-r6ZMdo.js +15 -0
  113. package/dist/platforms/react/field-binding/field-adapter.d.ts +1 -1
  114. package/dist/platforms/react/field-binding/field-handle.d.ts +5 -2
  115. package/dist/platforms/react/form-bundle-context.d.ts +27 -0
  116. package/dist/platforms/react/hooks/types.d.ts +57 -38
  117. package/dist/platforms/react/hooks/use-form-bundle.d.ts +19 -4
  118. package/dist/platforms/react/hooks/use-form-flow.d.ts +40 -0
  119. package/dist/platforms/react/hooks/use-form-validation.d.ts +12 -6
  120. package/dist/platforms/react/hooks/useArrayLength.d.ts +6 -6
  121. package/dist/platforms/react/hooks/useFormControl.d.ts +7 -9
  122. package/dist/platforms/react/hooks/useFormControlValue.d.ts +18 -19
  123. package/dist/platforms/react/hooks/useSignalSubscription.d.ts +9 -1
  124. package/dist/platforms/react/i18n/context.d.ts +6 -1
  125. package/dist/platforms/react/i18n/hooks.d.ts +16 -10
  126. package/dist/platforms/react/i18n/provider.d.ts +9 -2
  127. package/dist/platforms/react/index.d.ts +7 -4
  128. package/dist/react.d.ts +22 -0
  129. package/dist/react.js +505 -0
  130. package/dist/runtime-token.d.ts +1 -2
  131. package/dist/safe-effect-BbtX3KuN.js +643 -0
  132. package/dist/schema-controller-CpiO2JoK.js +143 -0
  133. package/dist/signals.d.ts +15 -9
  134. package/dist/signals.js +11 -6
  135. package/dist/strategy-CoFSemuP.js +375 -0
  136. package/dist/type-guards-D-N_5Ddh.js +19 -0
  137. package/dist/validation-issue-B9mjI8jz.js +7 -0
  138. package/dist/validation-message-Ced9MGxs.js +194 -0
  139. package/dist/validation.js +9 -8
  140. package/dist/validators/email.js +5 -5
  141. package/dist/validators/future-date.js +8 -8
  142. package/dist/validators/integer.js +3 -3
  143. package/dist/validators/is-date.js +4 -4
  144. package/dist/validators/is-number.js +4 -4
  145. package/dist/validators/max-age.js +8 -9
  146. package/dist/validators/max-date.js +8 -8
  147. package/dist/validators/max-length.js +7 -7
  148. package/dist/validators/max.js +4 -4
  149. package/dist/validators/min-age.js +10 -8
  150. package/dist/validators/min-date.js +3 -3
  151. package/dist/validators/min-length.js +5 -5
  152. package/dist/validators/min.js +4 -4
  153. package/dist/validators/multiple-of.js +11 -7
  154. package/dist/validators/non-negative.js +3 -3
  155. package/dist/validators/non-zero.js +3 -3
  156. package/dist/validators/past-date.js +8 -8
  157. package/dist/validators/pattern.js +5 -5
  158. package/dist/validators/phone.js +11 -9
  159. package/dist/validators/required.js +2 -2
  160. package/dist/validators/url.js +48 -12
  161. package/dist/validators.js +17 -17
  162. package/docs/llms/01-api-reference.md +60 -34
  163. package/docs/llms/02-quick-start.md +111 -80
  164. package/docs/llms/03-api-signatures.md +368 -153
  165. package/docs/llms/04-common-patterns.md +58 -56
  166. package/docs/llms/05-common-mistakes.md +69 -44
  167. package/docs/llms/06-troubleshooting.md +14 -9
  168. package/docs/llms/07-complete-import.md +74 -43
  169. package/docs/llms/08-form-types.md +11 -4
  170. package/docs/llms/09-formschema.md +131 -83
  171. package/docs/llms/10-arrays.md +119 -69
  172. package/docs/llms/11-async-watchfield.md +2 -2
  173. package/docs/llms/13-multi-step.md +134 -63
  174. package/docs/llms/14-extended-mistakes.md +20 -17
  175. package/docs/llms/15-project-structure.md +221 -74
  176. package/docs/llms/16-ui-components.md +55 -42
  177. package/docs/llms/17-nonexistent-api.md +199 -32
  178. package/docs/llms/18-conditional-fields.md +66 -32
  179. package/docs/llms/19-reading-values.md +15 -3
  180. package/docs/llms/20-compute-vs-watch.md +16 -10
  181. package/docs/llms/21-array-operations.md +76 -26
  182. package/docs/llms/22-cycle-detection.md +1 -1
  183. package/docs/llms/23-copy-from.md +2 -2
  184. package/docs/llms/24-sync-fields.md +6 -5
  185. package/docs/llms/25-reset-when.md +14 -7
  186. package/docs/llms/26-transform-value.md +4 -4
  187. package/docs/llms/27-revalidate-when.md +16 -15
  188. package/docs/llms/28-submit-and-reset.md +276 -128
  189. package/docs/llms/29-async-preload.md +40 -30
  190. package/docs/llms/30-type-safety-recipes.md +105 -51
  191. package/docs/llms/31-async-validator-debounce.md +96 -53
  192. package/docs/llms/33-validation-strategy.md +178 -66
  193. package/docs/llms/34-i18n.md +69 -43
  194. package/docs/llms/35-unified-contract.md +307 -0
  195. package/docs/llms/36-issue-messages.md +284 -0
  196. package/docs/llms/37-compiled-schema.md +332 -0
  197. package/docs/llms/38-form-flow.md +397 -0
  198. package/llms-index.json +1 -1
  199. package/llms.txt +6968 -3278
  200. package/package.json +23 -4
  201. package/dist/behaviors-value-C7dSEhCc.js +0 -134
  202. package/dist/create-model-B8U-COv-.js +0 -103
  203. package/dist/date-utils-dTT_x_Be.js +0 -31
  204. package/dist/form/create-core-form.d.ts +0 -70
  205. package/dist/form/factories/index.d.ts +0 -6
  206. package/dist/form/factories/node-factory.d.ts +0 -189
  207. package/dist/form/form-submitter.d.ts +0 -121
  208. package/dist/form/nodes/array-node.d.ts +0 -276
  209. package/dist/form/nodes/field-node.d.ts +0 -297
  210. package/dist/form/nodes/form-node.d.ts +0 -326
  211. package/dist/form/nodes/group-node.d.ts +0 -284
  212. package/dist/form/nodes/model-array-node.d.ts +0 -121
  213. package/dist/form/nodes/subscription-manager.d.ts +0 -180
  214. package/dist/form/status-machine.d.ts +0 -115
  215. package/dist/form/types/deep-schema.d.ts +0 -107
  216. package/dist/form/types/form-proxy.d.ts +0 -141
  217. package/dist/form/unique-id.d.ts +0 -45
  218. package/dist/form/validation/config.d.ts +0 -73
  219. package/dist/form/validation/error-handler.d.ts +0 -166
  220. package/dist/form/validators/validation-error.d.ts +0 -8
  221. package/dist/index-BrNkQj1y.js +0 -105
  222. package/dist/loader-Dv_Hl7JC.js +0 -216
  223. package/dist/model-signals-proxy-2vqS243J.js +0 -250
  224. package/dist/node-DGEFMTQu.js +0 -18
  225. package/dist/strategy-BXS_gBfz.js +0 -170
  226. package/dist/validation-error-B-U3RsV0.js +0 -11
@@ -1,23 +1,25 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
4
  * Фабрика валидатора, проверяющего что число кратно заданному.
4
5
  *
5
6
  * Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
6
7
  *
7
- * @param divisor - Делитель: значение должно быть кратно ему
8
- * @param options - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
8
+ * @param divisor - Делитель: значение должно быть кратно ему. Конечное число, не равное нулю, —
9
+ * иначе ошибка конфигурации (`RangeError`) при создании правила: кратность нулю вырождена.
10
+ * @param options - Опции валидатора ({@link RuleOptions}). В `params` ошибки автоматически
9
11
  * попадает `multipleOf` (делитель).
10
- * @returns Чистый валидатор {@link Validator} для числового поля
12
+ * @returns Правило {@link Rule} для числового поля
11
13
  *
12
14
  * @example Проверка кратности
13
15
  * ```typescript
14
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
16
+ * import { defineValidation, validate } from '@reformer/core/validation';
15
17
  * import { multipleOf } from '@reformer/core/validators';
16
18
  *
17
19
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
18
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
19
- * validate(model.$.rating, [multipleOf(0.5, { message: 'Только шаг 0.5' })]);
20
+ * const validation = defineValidation<MyForm>(({ model }) => {
21
+ * validate(model.$.rating, [multipleOf(0.5, { code: 'rating.multipleOf' })]);
20
22
  * });
21
23
  * ```
22
24
  */
23
- export declare function multipleOf<TForm = unknown, TField extends number | null | undefined = number>(divisor: number, options?: ValidateOptions): Validator<TForm, TField>;
25
+ export declare function multipleOf(divisor: number, options?: RuleOptions): Rule<number | null | undefined>;
@@ -1,21 +1,22 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
4
  * Фабрика валидатора, проверяющего что число неотрицательное (`≥ 0`).
4
5
  *
5
6
  * Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
6
7
  *
7
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
8
- * @returns Чистый валидатор {@link Validator} для числового поля
8
+ * @param options - Опции валидатора ({@link RuleOptions}): `code`, `params`
9
+ * @returns Правило {@link Rule} для числового поля
9
10
  *
10
11
  * @example Проверка неотрицательности
11
12
  * ```typescript
12
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
13
+ * import { defineValidation, validate } from '@reformer/core/validation';
13
14
  * import { nonNegative } from '@reformer/core/validators';
14
15
  *
15
16
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
16
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
17
- * validate(model.$.balance, [nonNegative({ message: 'Баланс не может быть отрицательным' })]);
17
+ * const validation = defineValidation<MyForm>(({ model }) => {
18
+ * validate(model.$.balance, [nonNegative({ code: 'balance.nonNegative' })]);
18
19
  * });
19
20
  * ```
20
21
  */
21
- export declare function nonNegative<TForm = unknown, TField extends number | null | undefined = number>(options?: ValidateOptions): Validator<TForm, TField>;
22
+ export declare function nonNegative(options?: RuleOptions): Rule<number | null | undefined>;
@@ -1,21 +1,22 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
4
  * Фабрика валидатора, проверяющего что число не равно нулю.
4
5
  *
5
6
  * Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
6
7
  *
7
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
8
- * @returns Чистый валидатор {@link Validator} для числового поля
8
+ * @param options - Опции валидатора ({@link RuleOptions}): `code`, `params`
9
+ * @returns Правило {@link Rule} для числового поля
9
10
  *
10
11
  * @example Проверка «не ноль»
11
12
  * ```typescript
12
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
13
+ * import { defineValidation, validate } from '@reformer/core/validation';
13
14
  * import { nonZero } from '@reformer/core/validators';
14
15
  *
15
16
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
16
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
17
- * validate(model.$.divisor, [nonZero({ message: 'Не может быть нулём' })]);
17
+ * const validation = defineValidation<MyForm>(({ model }) => {
18
+ * validate(model.$.divisor, [nonZero({ code: 'divisor.nonZero' })]);
18
19
  * });
19
20
  * ```
20
21
  */
21
- export declare function nonZero<TForm = unknown, TField extends number | null | undefined = number>(options?: ValidateOptions): Validator<TForm, TField>;
22
+ export declare function nonZero(options?: RuleOptions): Rule<number | null | undefined>;
@@ -1,22 +1,23 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
4
  * Фабрика валидатора, проверяющего что дата не в будущем.
4
5
  *
5
6
  * Дата не должна быть позже сегодняшнего дня (сравнение по нормализованным датам).
6
7
  * Пустые и невалидные даты пропускаются (используйте {@link required} и {@link isDate}).
7
8
  *
8
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
9
- * @returns Чистый валидатор {@link Validator} для поля даты (`string | Date`)
9
+ * @param options - Опции валидатора ({@link RuleOptions}): `code`, `params`
10
+ * @returns Правило {@link Rule} для поля даты (`string | Date`)
10
11
  *
11
12
  * @example Дата не в будущем
12
13
  * ```typescript
13
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
14
+ * import { defineValidation, validate } from '@reformer/core/validation';
14
15
  * import { required, pastDate } from '@reformer/core/validators';
15
16
  *
16
17
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
17
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
18
- * validate(model.$.birthDate, [required(), pastDate({ message: 'Дата рождения не может быть в будущем' })]);
18
+ * const validation = defineValidation<MyForm>(({ model }) => {
19
+ * validate(model.$.birthDate, [required(), pastDate({ code: 'birthDate.pastDate' })]);
19
20
  * });
20
21
  * ```
21
22
  */
22
- export declare function pastDate<TForm = unknown, TField extends string | Date | null | undefined = string | Date>(options?: ValidateOptions): Validator<TForm, TField>;
23
+ export declare function pastDate(options?: RuleOptions): Rule<string | Date | null | undefined>;
@@ -1,4 +1,5 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
4
  * Фабрика валидатора регулярного выражения.
4
5
  *
@@ -6,20 +7,20 @@ import { Validator, ValidateOptions } from '../types/validation-schema';
6
7
  * для обязательности).
7
8
  *
8
9
  * @param regex - Регулярное выражение для проверки значения
9
- * @param options - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
10
+ * @param options - Опции валидатора ({@link RuleOptions}). В `params` ошибки автоматически
10
11
  * попадает `pattern` (строка-источник regex).
11
- * @returns Чистый валидатор {@link Validator} для строкового поля
12
+ * @returns Правило {@link Rule} для строкового поля
12
13
  *
13
14
  * @example Проверка по регулярному выражению
14
15
  * ```typescript
15
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
16
+ * import { defineValidation, validate } from '@reformer/core/validation';
16
17
  * import { required, pattern } from '@reformer/core/validators';
17
18
  *
18
19
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
19
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
20
- * validate(model.$.name, [pattern(/^[a-zA-Zа-яА-Я]+$/, { message: 'Только буквы' })]);
21
- * validate(model.$.phone, [required(), pattern(/^\+7 \(\d{3}\) \d{3}-\d{2}-\d{2}$/, { message: 'Формат +7 (999) 123-45-67' })]);
20
+ * const validation = defineValidation<MyForm>(({ model }) => {
21
+ * validate(model.$.name, [pattern(/^[a-zA-Zа-яА-Я]+$/, { code: 'name.pattern' })]);
22
+ * validate(model.$.phone, [required(), pattern(/^\+7 \(\d{3}\) \d{3}-\d{2}-\d{2}$/, { code: 'phone.pattern' })]);
22
23
  * });
23
24
  * ```
24
25
  */
25
- export declare function pattern<TForm = unknown, TField extends string | null | undefined = string>(regex: RegExp, options?: ValidateOptions): Validator<TForm, TField>;
26
+ export declare function pattern(regex: RegExp, options?: RuleOptions): Rule<string | null | undefined>;
@@ -1,4 +1,5 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
4
  * Формат проверки номера телефона для валидатора {@link phone}.
4
5
  *
@@ -9,10 +10,10 @@ import { Validator, ValidateOptions } from '../types/validation-schema';
9
10
  */
10
11
  export type PhoneFormat = 'international' | 'ru' | 'us' | 'any';
11
12
  /**
12
- * Опции валидатора {@link phone}. Расширяют {@link ValidateOptions} (`message`, `params`)
13
+ * Опции валидатора {@link phone}. Расширяют {@link RuleOptions} (`code`, `params`)
13
14
  * выбором формата номера.
14
15
  */
15
- export interface PhoneValidatorOptions extends ValidateOptions {
16
+ export interface PhoneValidatorOptions extends RuleOptions {
16
17
  /** Формат проверки {@link PhoneFormat}. По умолчанию `'any'`. */
17
18
  format?: PhoneFormat;
18
19
  }
@@ -24,17 +25,17 @@ export interface PhoneValidatorOptions extends ValidateOptions {
24
25
  *
25
26
  * @param options - Опции валидатора {@link PhoneValidatorOptions}. В `params` ошибки
26
27
  * автоматически попадает выбранный `format`.
27
- * @returns Чистый валидатор {@link Validator} для строкового поля
28
+ * @returns Правило {@link Rule} для строкового поля
28
29
  *
29
30
  * @example Проверка номера телефона
30
31
  * ```typescript
31
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
32
+ * import { defineValidation, validate } from '@reformer/core/validation';
32
33
  * import { required, phone } from '@reformer/core/validators';
33
34
  *
34
35
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
35
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
36
+ * const validation = defineValidation<MyForm>(({ model }) => {
36
37
  * validate(model.$.phone, [required(), phone({ format: 'ru' })]);
37
38
  * });
38
39
  * ```
39
40
  */
40
- export declare function phone<TForm = unknown, TField extends string | null | undefined = string>(options?: PhoneValidatorOptions): Validator<TForm, TField>;
41
+ export declare function phone(options?: PhoneValidatorOptions): Rule<string | null | undefined>;
@@ -1,27 +1,29 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
4
  * Фабрика валидатора обязательного поля.
4
5
  *
5
6
  * Возвращает чистую функцию-валидатор `(value, control, root)`. Передаётся в `validate()`.
6
7
  *
7
8
  * Пустыми считаются: `null`, `undefined`, `''` (пустая строка), `[]` (пустой массив —
8
- * обязательный multi-select / FormArray без выбранных элементов).
9
+ * обязательный multi-select / FieldArray без выбранных элементов), `NaN` (так выглядит очищенный
10
+ * числовой ввод).
9
11
  * Для boolean полей требуется значение `true`.
10
12
  *
11
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
12
- * @returns Чистый валидатор {@link Validator} для поля схемы
13
+ * @param options - Опции валидатора ({@link RuleOptions}): `code`, `params`
14
+ * @returns Правило {@link Rule} для поля схемы
13
15
  *
14
16
  * @example Обязательные поля в схеме формы
15
17
  * ```typescript
16
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
18
+ * import { defineValidation, validate } from '@reformer/core/validation';
17
19
  * import { required } from '@reformer/core/validators';
18
20
  *
19
21
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
20
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
22
+ * const validation = defineValidation<MyForm>(({ model }) => {
21
23
  * validate(model.$.email, [required()]);
22
- * validate(model.$.phone, [required({ message: 'Укажите номер телефона' })]);
23
- * validate(model.$.agreeToTerms, [required({ message: 'Необходимо принять условия' })]);
24
+ * validate(model.$.phone, [required({ code: 'phone.required' })]);
25
+ * validate(model.$.agreeToTerms, [required({ code: 'agreeToTerms.required' })]);
24
26
  * });
25
27
  * ```
26
28
  */
27
- export declare function required<TForm = unknown, TField = unknown>(options?: ValidateOptions): Validator<TForm, TField>;
29
+ export declare function required(options?: RuleOptions): Rule<unknown>;
@@ -1,14 +1,16 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
- * Опции валидатора {@link url}. Расширяют {@link ValidateOptions} (`message`, `params`)
4
+ * Опции валидатора {@link url}. Расширяют {@link RuleOptions} (`code`, `params`)
4
5
  * настройками проверки протокола.
5
6
  */
6
- export interface UrlValidatorOptions extends ValidateOptions {
7
- /** Требовать наличие протокола (`http://` или `https://`). По умолчанию `false`. */
7
+ export interface UrlValidatorOptions extends RuleOptions {
8
+ /** Требовать протокол (`схема://`). По умолчанию `false`: `example.com` допустим. */
8
9
  requireProtocol?: boolean;
9
10
  /**
10
- * Список разрешённых протоколов (без `://`), например `['https']`. Если задан,
11
- * значение с иным протоколом даёт ошибку с кодом `url_protocol`.
11
+ * Разрешённые протоколы (без `://`), сравнение без учёта регистра, например `['https']`. Не
12
+ * задан или пуст — `http` и `https`. Значение с иным протоколом даёт замечание `url_protocol`;
13
+ * при заданном списке — и значение без протокола.
12
14
  */
13
15
  allowedProtocols?: string[];
14
16
  }
@@ -16,23 +18,28 @@ export interface UrlValidatorOptions extends ValidateOptions {
16
18
  * Фабрика валидатора URL.
17
19
  *
18
20
  * Пустые значения (`''`/`null`/`undefined`) пропускаются (используйте {@link required}
19
- * для обязательности). При `requireProtocol` протокол обязателен; `allowedProtocols`
20
- * дополнительно ограничивает набор допустимых протоколов.
21
+ * для обязательности).
22
+ *
23
+ * Контракт адреса: разбор — `new URL`; хост — `localhost`, домен с буквенной зоной (в том числе
24
+ * кириллический и punycode), IPv4 или `[IPv6]`; порт допустим. Запрещены пробелы и userinfo
25
+ * (`user:pass@`). Протокол необязателен (`example.com`), пока не задан `requireProtocol`; по
26
+ * умолчанию разрешены `http` и `https`, чужой протокол — замечание `url_protocol` с
27
+ * `params.allowedProtocols`. Свой `code` из опций заменяет оба встроенных кода.
21
28
  *
22
29
  * @param options - Опции валидатора {@link UrlValidatorOptions}
23
- * @returns Чистый валидатор {@link Validator} для строкового поля
30
+ * @returns Правило {@link Rule} для строкового поля
24
31
  *
25
32
  * @example Проверка URL
26
33
  * ```typescript
27
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
34
+ * import { defineValidation, validate } from '@reformer/core/validation';
28
35
  * import { required, url } from '@reformer/core/validators';
29
36
  *
30
37
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
31
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
32
- * validate(model.$.website, [required(), url({ message: 'Введите корректный URL' })]);
38
+ * const validation = defineValidation<MyForm>(({ model }) => {
39
+ * validate(model.$.website, [required(), url({ code: 'website.url' })]);
33
40
  * // Требовать протокол и ограничить схему только https:
34
41
  * validate(model.$.homepage, [url({ requireProtocol: true, allowedProtocols: ['https'] })]);
35
42
  * });
36
43
  * ```
37
44
  */
38
- export declare function url<TForm = unknown, TField extends string | null | undefined = string>(options?: UrlValidatorOptions): Validator<TForm, TField>;
45
+ export declare function url(options?: UrlValidatorOptions): Rule<string | null | undefined>;
@@ -0,0 +1,8 @@
1
+ import { ValidationIssue } from '../types/contracts';
2
+ import { RuleOptions } from '../types/validation-schema';
3
+ /**
4
+ * @param code - Встроенный код правила; по нему ищется текст в словаре локали (`validation.<code>`).
5
+ * @param options - Опции правила: свой код и дополнительные параметры.
6
+ * @param params - Параметры, которые правило заполняет само; параметры из `options` важнее.
7
+ */
8
+ export declare function validationIssue(code: string, options: RuleOptions | undefined, params?: Record<string, unknown>): ValidationIssue;
@@ -28,7 +28,7 @@ export type LocalizableText = string | MessageDescriptor;
28
28
  *
29
29
  * @example
30
30
  * ```ts
31
- * { value: model.$.email, component: Input, componentProps: { label: msg('profile.email.label') } }
31
+ * { model: model.$.email, component: Input, componentProps: { label: msg('profile.email.label') } }
32
32
  * ```
33
33
  */
34
34
  export declare function msg(key: string, values?: Readonly<Record<string, unknown>>, defaultMessage?: string): MessageDescriptor;
@@ -16,6 +16,8 @@ declare const _default: {
16
16
  "validation.max": "Must be at most {max}",
17
17
  "validation.minLength": "Enter at least {minLength, plural, one{# character} other{# characters}}",
18
18
  "validation.maxLength": "Enter no more than {maxLength, plural, one{# character} other{# characters}}",
19
+ "validation.minItems": "At least {minLength, plural, one{# item} other{# items}}",
20
+ "validation.maxItems": "No more than {maxLength, plural, one{# item} other{# items}}",
19
21
  "validation.isNumber": "Enter a number",
20
22
  "validation.integer": "Enter a whole number",
21
23
  "validation.multipleOf": "Must be a multiple of {multipleOf}",
@@ -38,7 +40,9 @@ declare const _default: {
38
40
  "validation.maxTotalFileSize": "The total size of the files exceeds {maxTotalFileSize}",
39
41
  "validation.fileExists": "File {fileName} has already been added",
40
42
  "validation.uploadAborted": "Upload cancelled",
41
- "validation.uploadFailed": "Failed to upload {fileName}"
43
+ "validation.uploadFailed": "Failed to upload {fileName}",
44
+
45
+ "validation.ruleFailed": "Could not check this field. Try again"
42
46
  }
43
47
  ;
44
48
 
@@ -21,11 +21,18 @@ export interface LocaleStore {
21
21
  subscribe(listener: () => void): () => void;
22
22
  /** Запросить язык. Повторный запрос того же языка, пока он грузится или уже показан, — no-op. */
23
23
  setLang(lang: string): void;
24
+ /** Повторить запрос языка, загрузка которого упала. Без ошибки — no-op. */
25
+ retry(): void;
24
26
  }
25
27
  /** Настройки хранилища. */
26
28
  export interface LocaleStoreOptions {
27
29
  /** Вызывается при отказе загрузки языка, который всё ещё запрошен. */
28
30
  readonly onError?: (error: unknown, lang: string) => void;
31
+ /**
32
+ * Локаль, которая уже на экране (прежнее хранилище провайдера с другим загрузчиком). Пока новый
33
+ * загрузчик не отдал язык, на экране остаётся она, а не «ничего не загружено».
34
+ */
35
+ readonly previous?: FormLocale;
29
36
  }
30
37
  /**
31
38
  * Создаёт хранилище. Загрузка при создании НЕ начинается: начальное состояние считается чисто —
@@ -8,7 +8,8 @@
8
8
  * категории берутся из {@link Intl.PluralRules} активной локали, `#` подставляет само число через
9
9
  * {@link Intl.NumberFormat};
10
10
  * - **выбор по значению** — `{gender, select, male{он} female{она} other{оно}}`;
11
- * - **экранирование** — апострофом, как в ICU: `'{'` → `{`, `'}'` → `}`, `''` → `'`.
11
+ * - **экранирование** — апострофом, как в ICU: `'{'` → `{`, `'}'` → `}`, `''` → `'`; как в
12
+ * `intl-messageformat`, литерал открывает и апостроф перед `<` и `>`.
12
13
  *
13
14
  * Три свойства, ради которых формат устроен именно так:
14
15
  *
@@ -17,9 +18,12 @@
17
18
  * `{count, plural, ...}` выведет эти символы, а не выполнит их. Замена регулярным выражением
18
19
  * такой гарантии не даёт.
19
20
  * 2. **Синтаксис — честное подмножество ICU.** Любое сообщение, которое понимает этот модуль,
20
- * `intl-messageformat` (в режиме `ignoreTag`, со строковыми и числовыми значениями) понимает так
21
- * же и выводит посимвольно то же самое; это проверено дифференциальным тестом на общем наборе
22
- * сообщений (`tests/i18n/message-format.differential.test.ts`). Отсюда страховка из контракта:
21
+ * `intl-messageformat` (в режиме `ignoreTag`, со строковыми значениями и конечными числами;
22
+ * значение `plural` — число) понимает так же и выводит посимвольно то же самое; это проверено
23
+ * дифференциальным и property-тестами (`tests/i18n/message-format.differential.test.ts`,
24
+ * `message-format.property.test.ts`). Чего не понимает эталон — повтор ключа ветки, `=N` с не
25
+ * целым числом или в `select`, символы синтаксиса ICU в имени, — не понимает и этот модуль.
26
+ * Отсюда страховка из контракта:
23
27
  * если подмножества перестанет хватать, библиотека подставляется под тот же вызов, и словари
24
28
  * переписывать не придётся.
25
29
  * 3. **Ошибка синтаксиса и отсутствие ветки `other` — отказ на разборе**, а не молчаливая
@@ -30,6 +34,8 @@
30
34
  * отвергаются на разборе. Сообщение с ними не пройдёт в словарь, а не отформатируется молча
31
35
  * неправильно. Заметь: голое `{n}` форматируется как `String(n)` и здесь, и в `intl-messageformat`
32
36
  * (`{year}` → `2026`, а не `2 026`); по локали форматируется только `#` внутри `plural`.
37
+ * Вложенность аргументов — не глубже 100 уровней: глубже рекурсивный разбор исчерпал бы стек
38
+ * (`RangeError`) вместо внятного отказа.
33
39
  * - **Пропущенный аргумент не бросает исключение**, а подставляет заметный маркер `⟦name⟧`: строка
34
40
  * интерфейса не должна ронять панель. Поведение настраивается через `onMissingArgument`.
35
41
  *
@@ -73,6 +79,20 @@ export interface MessageFormatOptions {
73
79
  export declare class MessageSyntaxError extends Error {
74
80
  readonly name = "MessageSyntaxError";
75
81
  }
82
+ /**
83
+ * Код языка, пригодный для `Intl`. Некорректный (не BCP 47) заменяется на `en` — с предупреждением
84
+ * в dev, один раз на код. Код может прийти извне (язык из адресной строки), и `RangeError` из
85
+ * `Intl` ронял бы рендер на первом же `plural`, числе или дате.
86
+ *
87
+ * @param code - Код языка локали.
88
+ * @returns Тот же код либо `en`.
89
+ */
90
+ export declare function intlLocale(code: string): string;
91
+ /**
92
+ * Значение как текст. Значение, которое нельзя привести к строке (`Object.create(null)`, объект
93
+ * с бросающим `toString`), — пустая строка: одно такое значение не роняет всё сообщение.
94
+ */
95
+ export declare function toText(value: unknown): string;
76
96
  /**
77
97
  * Разбирает сообщение в дерево. Бросает {@link MessageSyntaxError} на ошибке синтаксиса и на
78
98
  * `plural`/`select` без ветки `other`.
@@ -16,6 +16,8 @@ declare const _default: {
16
16
  "validation.max": "Не больше {max}",
17
17
  "validation.minLength": "Не меньше {minLength, plural, one{# символа} few{# символов} many{# символов} other{# символа}}",
18
18
  "validation.maxLength": "Не больше {maxLength, plural, one{# символа} few{# символов} many{# символов} other{# символа}}",
19
+ "validation.minItems": "Не меньше {minLength, plural, one{# элемента} few{# элементов} many{# элементов} other{# элемента}}",
20
+ "validation.maxItems": "Не больше {maxLength, plural, one{# элемента} few{# элементов} many{# элементов} other{# элемента}}",
19
21
  "validation.isNumber": "Введите число",
20
22
  "validation.integer": "Введите целое число",
21
23
  "validation.multipleOf": "Число должно быть кратно {multipleOf}",
@@ -38,7 +40,9 @@ declare const _default: {
38
40
  "validation.maxTotalFileSize": "Суммарный размер файлов больше {maxTotalFileSize}",
39
41
  "validation.fileExists": "Файл {fileName} уже добавлен",
40
42
  "validation.uploadAborted": "Загрузка прервана",
41
- "validation.uploadFailed": "Не удалось загрузить файл {fileName}"
43
+ "validation.uploadFailed": "Не удалось загрузить файл {fileName}",
44
+
45
+ "validation.ruleFailed": "Не удалось проверить поле. Повторите попытку"
42
46
  }
43
47
  ;
44
48
 
@@ -1,5 +1,16 @@
1
1
  import { FormLocale, Messages } from './locale';
2
2
  import { MessageValues } from './message-format';
3
+ /**
4
+ * Сообщение произвольного словаря по правилам языка `code`; `undefined`, если ключа нет, значение
5
+ * не строка либо шаблон не разобрался. Разбор кэшируется по объекту словаря, поэтому словарь
6
+ * должен быть стабильной ссылкой (константа модуля), а не литералом в теле компонента.
7
+ *
8
+ * @param messages - Словарь: ключ → шаблон сообщения. Нестроковые значения пропускаются.
9
+ * @param code - Код языка для `plural` и форматирования чисел.
10
+ * @param key - Ключ сообщения.
11
+ * @param values - Значения подстановок.
12
+ */
13
+ export declare function formatMessage(messages: Readonly<Record<string, unknown>>, code: string, key: string, values?: MessageValues): string | undefined;
3
14
  /**
4
15
  * Перевод ключа пакета: словарь локали, затем встроенная английская таблица пакета, затем сам
5
16
  * ключ. Английская таблица форматируется по английским правилам — её множественные формы и
@@ -1,18 +1,53 @@
1
- import { ValidationError } from '../form/types/contracts';
1
+ import { ValidationIssue } from '../form/types/contracts';
2
2
  import { I18nHandle } from './translator';
3
3
  /**
4
- * Отображаемый текст ошибки валидации. Порядок источников — в шапке модуля.
4
+ * Текст замечания в словаре формы: шаблон с параметрами либо функция.
5
5
  *
6
- * @param error - Ошибка от правила: `code`, `message`, `messageKey`, `params`.
6
+ * Шаблон — тот же формат сообщений, что в словарях локали: `{minLength}`, `plural`, `select`.
7
+ * Параметры в него приходят подготовленными: дата — по языку, массив — перечнем, размер файла —
8
+ * строкой с единицей. Число шаблон печатает как есть, без разрядов: «50 000 ₽» пишут готовым
9
+ * текстом либо функцией, которая форматирует число сама.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const byTemplate: IssueMessage = 'Не меньше {minLength} символов';
14
+ * const byFunction: IssueMessage = (params, i18n) => `Не меньше ${i18n.number(Number(params.min))} ₽`;
15
+ * ```
16
+ */
17
+ export type IssueMessage = string | ((params: Readonly<Record<string, unknown>>, i18n: I18nHandle) => string);
18
+ /**
19
+ * Словарь формы: код замечания → текст. Ключ — `code` замечания: встроенный (`required`) либо
20
+ * свой (`loanAmount.required`).
21
+ */
22
+ export type IssueMessages = Readonly<Record<string, IssueMessage>>;
23
+ /**
24
+ * Объявить словарь формы. Возвращает аргумент как есть — функция нужна типам: коды остаются
25
+ * литералами, а значения проверяются как {@link IssueMessage}.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * export const loanMessages = defineIssueMessages({
30
+ * 'loanAmount.required': 'Укажите сумму кредита',
31
+ * 'loanPurpose.minLength': 'Минимум {minLength} символов',
32
+ * 'carYear.max': (params) => `Не позднее ${String(params.max)}`,
33
+ * });
34
+ * ```
35
+ */
36
+ export declare function defineIssueMessages<const Messages extends IssueMessages>(messages: Messages): Messages;
37
+ /**
38
+ * Отображаемый текст замечания валидации. Порядок источников — в шапке модуля.
39
+ *
40
+ * @param issue - Замечание от правила: `code` и `params`.
7
41
  * @param i18n - Ручка активной локали (`createI18n` / `useI18n`).
42
+ * @param messages - Словарь формы; его записи важнее словаря локали.
8
43
  *
9
44
  * @example
10
45
  * ```ts
11
- * resolveValidationError({ code: 'minLength', message: '', params: { minLength: 8 } }, i18n);
46
+ * resolveIssueMessage({ code: 'minLength', params: { minLength: 8 } }, i18n);
12
47
  * // 'Enter at least 8 characters' · в русской локали — 'Не меньше 8 символов'
13
48
  *
14
- * resolveValidationError({ code: 'required', message: 'Укажите телефон' }, i18n);
15
- * // 'Укажите телефон' — явное сообщение автора важнее словаря
49
+ * resolveIssueMessage({ code: 'phone.required' }, i18n, { 'phone.required': 'Укажите телефон' });
50
+ * // 'Укажите телефон' — текст поля из словаря формы
16
51
  * ```
17
52
  */
18
- export declare function resolveValidationError(error: ValidationError, i18n: I18nHandle): string;
53
+ export declare function resolveIssueMessage(issue: ValidationIssue, i18n: I18nHandle, messages?: IssueMessages): string;
package/dist/i18n.d.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  /**
2
- * Подпуть `@reformer/core/i18n` — локализация форм: объект локали, загрузка словарей, провайдер,
3
- * перевод и форматирование, описатели авторских подписей.
2
+ * Подпуть `@reformer/core/i18n` — локализация форм без React: объект локали, загрузка словарей,
3
+ * перевод и форматирование, тексты ошибок, описатели авторских подписей.
4
4
  *
5
- * Вторая точка сшивки слоёв после корневого `index.ts`: чистая часть лежит в `src/i18n/`
6
- * (без React), привязка к React — в `src/platforms/react/i18n/`. Из главной бочки `@reformer/core`
7
- * этот модуль не реэкспортируется: канонический импорт один, а контекст обязан существовать в
8
- * единственном экземпляре на все пакеты `@reformer/*`.
5
+ * Провайдер и хуки (`I18nProvider`, `useI18n`, `useMessages`, `useIssueMessage`) отдаёт вход
6
+ * `@reformer/core/react`. Из главной бочки `@reformer/core` этот модуль не реэкспортируется:
7
+ * канонический импорт один.
9
8
  *
10
9
  * @group i18n
11
10
  * @module i18n
@@ -20,12 +19,8 @@ export { createLocaleStore } from './i18n/locale-store';
20
19
  export type { LocaleLoad, LocaleStore, LocaleStoreState, LocaleStoreOptions, } from './i18n/locale-store';
21
20
  export { createI18n, translateBuiltin } from './i18n/translator';
22
21
  export type { I18nHandle } from './i18n/translator';
23
- export { resolveValidationError } from './i18n/validation-message';
22
+ export { resolveIssueMessage, defineIssueMessages } from './i18n/validation-message';
23
+ export type { IssueMessage, IssueMessages } from './i18n/validation-message';
24
24
  export { msg, defineMessages, isMessageDescriptor, MESSAGE_DESCRIPTOR } from './i18n/descriptor';
25
25
  export type { MessageDescriptor, LocalizableText } from './i18n/descriptor';
26
26
  export { resolveLocalized } from './i18n/resolve-localized';
27
- export { I18nProvider } from './platforms/react/i18n/provider';
28
- export type { I18nProviderProps, I18nStaticProviderProps, I18nLoadingProviderProps, } from './platforms/react/i18n/provider';
29
- export { useI18n, useMessages, useValidationMessage } from './platforms/react/i18n/hooks';
30
- export { I18N_CONTEXT_MARKER } from './platforms/react/i18n/context';
31
- export type { I18nContextValue } from './platforms/react/i18n/context';