@reformer/core 11.0.0-beta.6 → 11.0.0-beta.7
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/dist/behaviors.js +124 -124
- package/dist/create-model-B8U-COv-.js +103 -0
- package/dist/en-CjAqn7h0.js +41 -0
- package/dist/form/behaviors/internals.d.ts +9 -0
- package/dist/form/types/contracts.d.ts +6 -0
- package/dist/form/types/validation-schema.d.ts +13 -1
- package/dist/form/validation/operators.d.ts +6 -1
- package/dist/form/validators/validation-error.d.ts +8 -0
- package/dist/i18n/descriptor.d.ts +54 -0
- package/dist/i18n/en.json.d.ts +45 -0
- package/dist/i18n/loader.d.ts +71 -0
- package/dist/i18n/locale-store.d.ts +39 -0
- package/dist/i18n/locale.d.ts +90 -0
- package/dist/i18n/message-format.d.ts +116 -0
- package/dist/i18n/resolve-localized.d.ts +17 -0
- package/dist/i18n/ru.json.d.ts +45 -0
- package/dist/i18n/translator.d.ts +50 -0
- package/dist/i18n/validation-message.d.ts +18 -0
- package/dist/i18n.d.ts +31 -0
- package/dist/i18n.js +303 -0
- package/dist/index-BrNkQj1y.js +105 -0
- package/dist/index.js +639 -736
- package/dist/loader-Dv_Hl7JC.js +216 -0
- package/dist/locale/en.d.ts +2 -0
- package/dist/locale/en.js +5 -0
- package/dist/locale/en.json +42 -0
- package/dist/locale/index.d.ts +18 -0
- package/dist/locale/ru.d.ts +2 -0
- package/dist/locale/ru.js +41 -0
- package/dist/locale/ru.json +42 -0
- package/dist/locale.d.ts +2 -0
- package/dist/locale.js +9 -0
- package/dist/model/create-model.d.ts +17 -3
- package/dist/model/index.d.ts +3 -3
- package/dist/model/model-signals-proxy.d.ts +25 -0
- package/dist/model/types.d.ts +19 -5
- package/dist/model-signals-proxy-2vqS243J.js +250 -0
- package/dist/model.js +18 -16
- package/dist/platforms/react/hooks/types.d.ts +6 -3
- package/dist/platforms/react/hooks/useFormControlValue.d.ts +2 -1
- package/dist/platforms/react/i18n/context.d.ts +13 -0
- package/dist/platforms/react/i18n/hooks.d.ts +59 -0
- package/dist/platforms/react/i18n/provider.d.ts +52 -0
- package/dist/{strategy-DA3JwxsR.js → strategy-BXS_gBfz.js} +7 -7
- package/dist/validation-error-B-U3RsV0.js +11 -0
- package/dist/validation.js +1 -1
- package/dist/validators/email.js +5 -8
- package/dist/validators/future-date.js +8 -11
- package/dist/validators/integer.js +4 -7
- package/dist/validators/is-date.js +5 -8
- package/dist/validators/is-number.js +4 -7
- package/dist/validators/max-age.js +8 -11
- package/dist/validators/max-date.js +8 -11
- package/dist/validators/max-length.js +5 -8
- package/dist/validators/max.js +4 -7
- package/dist/validators/min-age.js +8 -11
- package/dist/validators/min-date.js +8 -11
- package/dist/validators/min-length.js +5 -8
- package/dist/validators/min.js +4 -7
- package/dist/validators/multiple-of.js +5 -8
- package/dist/validators/non-negative.js +4 -7
- package/dist/validators/non-zero.js +4 -7
- package/dist/validators/past-date.js +8 -11
- package/dist/validators/pattern.js +5 -8
- package/dist/validators/phone.js +6 -9
- package/dist/validators/required.js +4 -7
- package/dist/validators/url.js +9 -14
- package/dist/validators.js +84 -106
- package/docs/llms/03-api-signatures.md +6 -0
- package/docs/llms/10-arrays.md +30 -0
- package/docs/llms/34-i18n.md +272 -0
- package/llms-index.json +1 -1
- package/llms.txt +1589 -98
- package/package.json +22 -3
- package/dist/create-model-Dxh9cfLp.js +0 -97
- package/dist/model-signals-proxy-mV3WGdlO.js +0 -233
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { batch as y, signal as v, Signal as A, computed as w } from "@preact/signals-core";
|
|
2
|
+
const u = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function R(t) {
|
|
4
|
+
u.set(t, (u.get(t) ?? 0) + 1);
|
|
5
|
+
}
|
|
6
|
+
function D(t) {
|
|
7
|
+
const e = u.get(t);
|
|
8
|
+
e !== void 0 && (e <= 1 ? u.delete(t) : u.set(t, e - 1));
|
|
9
|
+
}
|
|
10
|
+
function _(t) {
|
|
11
|
+
return u.has(t);
|
|
12
|
+
}
|
|
13
|
+
const h = (t) => !(t === null || typeof t != "object" || Array.isArray(t) || t instanceof Date || typeof Blob < "u" && t instanceof Blob || typeof File < "u" && t instanceof File), o = (t, e) => t === "" ? String(e) : `${t}.${e}`, S = (t) => /^\d+$/.test(t), l = (t) => {
|
|
14
|
+
if (Array.isArray(t)) return t.map(l);
|
|
15
|
+
if (h(t)) {
|
|
16
|
+
const e = {};
|
|
17
|
+
for (const r of Object.keys(t)) e[r] = l(t[r]);
|
|
18
|
+
return e;
|
|
19
|
+
}
|
|
20
|
+
return t;
|
|
21
|
+
}, d = (t, e) => {
|
|
22
|
+
if (t === e) return !0;
|
|
23
|
+
if (Array.isArray(t) && Array.isArray(e))
|
|
24
|
+
return t.length !== e.length ? !1 : t.every((r, i) => d(r, e[i]));
|
|
25
|
+
if (h(t) && h(e)) {
|
|
26
|
+
const r = Object.keys(t), i = Object.keys(e);
|
|
27
|
+
return r.length !== i.length ? !1 : r.every((s) => d(t[s], e[s]));
|
|
28
|
+
}
|
|
29
|
+
return !1;
|
|
30
|
+
};
|
|
31
|
+
class j {
|
|
32
|
+
constructor(e, r) {
|
|
33
|
+
this.path = r;
|
|
34
|
+
const i = v(e);
|
|
35
|
+
i.__path = r, this.signal = i, this.initial = l(e);
|
|
36
|
+
}
|
|
37
|
+
kind = "leaf";
|
|
38
|
+
signal;
|
|
39
|
+
initial;
|
|
40
|
+
rebase(e) {
|
|
41
|
+
this.path = e, this.signal.__path = e;
|
|
42
|
+
}
|
|
43
|
+
/** Реактивное чтение (внутри effect/computed создаёт зависимость). */
|
|
44
|
+
read() {
|
|
45
|
+
return this.signal.value;
|
|
46
|
+
}
|
|
47
|
+
/** Нереактивный снимок. */
|
|
48
|
+
peek() {
|
|
49
|
+
return this.signal.peek();
|
|
50
|
+
}
|
|
51
|
+
set(e) {
|
|
52
|
+
this.signal.value = e;
|
|
53
|
+
}
|
|
54
|
+
resetToInitial() {
|
|
55
|
+
this.signal.value = l(this.initial);
|
|
56
|
+
}
|
|
57
|
+
captureInitial() {
|
|
58
|
+
this.initial = l(this.signal.peek());
|
|
59
|
+
}
|
|
60
|
+
dirty() {
|
|
61
|
+
return !d(this.signal.peek(), this.initial);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
class $ {
|
|
65
|
+
constructor(e, r) {
|
|
66
|
+
this.path = r;
|
|
67
|
+
for (const i of Object.keys(e))
|
|
68
|
+
this.children.set(i, c(e[i], o(r, i)));
|
|
69
|
+
}
|
|
70
|
+
kind = "group";
|
|
71
|
+
children = /* @__PURE__ */ new Map();
|
|
72
|
+
rebase(e) {
|
|
73
|
+
this.path = e;
|
|
74
|
+
for (const [r, i] of this.children) i.rebase(o(e, r));
|
|
75
|
+
}
|
|
76
|
+
/** Реактивное чтение поддерева (внутри effect/computed подписывает на все листья группы). */
|
|
77
|
+
read() {
|
|
78
|
+
const e = {};
|
|
79
|
+
for (const [r, i] of this.children) e[r] = i.read();
|
|
80
|
+
return e;
|
|
81
|
+
}
|
|
82
|
+
peek() {
|
|
83
|
+
const e = {};
|
|
84
|
+
for (const [r, i] of this.children) e[r] = i.peek();
|
|
85
|
+
return e;
|
|
86
|
+
}
|
|
87
|
+
set(e) {
|
|
88
|
+
if (e == null || typeof e != "object") return;
|
|
89
|
+
const r = e;
|
|
90
|
+
y(() => {
|
|
91
|
+
for (const [i, s] of this.children)
|
|
92
|
+
i in r && (s.kind === "leaf" && _(s.signal) || s.set(r[i]));
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
resetToInitial() {
|
|
96
|
+
y(() => {
|
|
97
|
+
for (const e of this.children.values()) e.resetToInitial();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
captureInitial() {
|
|
101
|
+
for (const e of this.children.values()) e.captureInitial();
|
|
102
|
+
}
|
|
103
|
+
dirty() {
|
|
104
|
+
for (const e of this.children.values()) if (e.dirty()) return !0;
|
|
105
|
+
return !1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
class x {
|
|
109
|
+
constructor(e, r) {
|
|
110
|
+
this.path = r, this.items = v(e.map((i, s) => c(i, o(r, s)))), this.initial = l(e);
|
|
111
|
+
}
|
|
112
|
+
kind = "array";
|
|
113
|
+
items;
|
|
114
|
+
initial;
|
|
115
|
+
rebase(e) {
|
|
116
|
+
this.path = e, this.items.peek().forEach((r, i) => r.rebase(o(e, i)));
|
|
117
|
+
}
|
|
118
|
+
reindex() {
|
|
119
|
+
this.items.peek().forEach((e, r) => e.rebase(o(this.path, r)));
|
|
120
|
+
}
|
|
121
|
+
push(e) {
|
|
122
|
+
const r = this.items.peek();
|
|
123
|
+
this.items.value = [...r, c(e, o(this.path, r.length))];
|
|
124
|
+
}
|
|
125
|
+
insertAt(e, r) {
|
|
126
|
+
const i = [...this.items.peek()];
|
|
127
|
+
i.splice(e, 0, c(r, o(this.path, e))), this.items.value = i, this.reindex();
|
|
128
|
+
}
|
|
129
|
+
removeAt(e) {
|
|
130
|
+
const r = [...this.items.peek()];
|
|
131
|
+
r.splice(e, 1), this.items.value = r, this.reindex();
|
|
132
|
+
}
|
|
133
|
+
move(e, r) {
|
|
134
|
+
const i = [...this.items.peek()], [s] = i.splice(e, 1);
|
|
135
|
+
s && i.splice(r, 0, s), this.items.value = i, this.reindex();
|
|
136
|
+
}
|
|
137
|
+
swap(e, r) {
|
|
138
|
+
const i = [...this.items.peek()];
|
|
139
|
+
e < 0 || r < 0 || e >= i.length || r >= i.length || e === r || ([i[e], i[r]] = [i[r], i[e]], this.items.value = i, this.reindex());
|
|
140
|
+
}
|
|
141
|
+
clear() {
|
|
142
|
+
this.items.value = [];
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Реактивное чтение массива. Читаем `items.value` (а не `.peek()`) — внутри effect/computed это
|
|
146
|
+
* подписка на СОСТАВ массива, поэтому push/removeAt/move ретригерят наравне с правкой элемента.
|
|
147
|
+
*/
|
|
148
|
+
read() {
|
|
149
|
+
return this.items.value.map((e) => e.read());
|
|
150
|
+
}
|
|
151
|
+
peek() {
|
|
152
|
+
return this.items.peek().map((e) => e.peek());
|
|
153
|
+
}
|
|
154
|
+
set(e) {
|
|
155
|
+
const r = Array.isArray(e) ? e : [];
|
|
156
|
+
this.items.value = r.map((i, s) => c(i, o(this.path, s)));
|
|
157
|
+
}
|
|
158
|
+
resetToInitial() {
|
|
159
|
+
this.set(l(this.initial));
|
|
160
|
+
}
|
|
161
|
+
captureInitial() {
|
|
162
|
+
this.initial = l(this.peek());
|
|
163
|
+
}
|
|
164
|
+
dirty() {
|
|
165
|
+
return !d(this.peek(), this.initial);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function c(t, e) {
|
|
169
|
+
return Array.isArray(t) ? new x(t, e) : h(t) ? new $(t, e) : new j(t, e);
|
|
170
|
+
}
|
|
171
|
+
const k = /* @__PURE__ */ new WeakMap();
|
|
172
|
+
function I(t) {
|
|
173
|
+
const e = w(() => t.read());
|
|
174
|
+
return {
|
|
175
|
+
get value() {
|
|
176
|
+
return e.value;
|
|
177
|
+
},
|
|
178
|
+
peek: () => e.peek(),
|
|
179
|
+
subscribe: (r) => e.subscribe(r),
|
|
180
|
+
valueOf: () => e.value,
|
|
181
|
+
toString: () => String(e.value),
|
|
182
|
+
toJSON: () => e.value,
|
|
183
|
+
brand: e.brand
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function b(t) {
|
|
187
|
+
if (t.kind === "leaf") return t.signal;
|
|
188
|
+
const e = k.get(t);
|
|
189
|
+
if (e) return e;
|
|
190
|
+
const r = I(t), i = t.kind === "group", s = (a) => i ? t.children.get(a) : S(a) ? t.items.value[Number(a)] : void 0, g = i ? {} : {
|
|
191
|
+
get length() {
|
|
192
|
+
return t.items.value.length;
|
|
193
|
+
}
|
|
194
|
+
}, m = new Proxy(g, {
|
|
195
|
+
get: (a, n, p) => {
|
|
196
|
+
if (n === "__path") return t.path;
|
|
197
|
+
if (n === "__kind") return t.kind;
|
|
198
|
+
if (typeof n != "string") return Reflect.get(r, n, r);
|
|
199
|
+
const f = s(n);
|
|
200
|
+
return f ? b(f) : !i && Reflect.has(a, n) ? Reflect.get(a, n, p) : Reflect.get(r, n, r);
|
|
201
|
+
},
|
|
202
|
+
set: (a, n, p) => {
|
|
203
|
+
if (!i && n === "value")
|
|
204
|
+
return t.set(p), !0;
|
|
205
|
+
const f = t.path === "" ? "model.$" : `model.$.${t.path}`;
|
|
206
|
+
throw new TypeError(
|
|
207
|
+
`[@reformer/core] ${f}: запись в «${String(n)}» ` + (i ? "узла-группы невозможна — группа читается целиком, а пишется по полям (model.$.<поле>.value) либо через model.patch(...)" : "узла-массива невозможна — массив заменяется целиком через .value, а элемент правится своим сигналом (model.$.<массив>[i].value)")
|
|
208
|
+
);
|
|
209
|
+
},
|
|
210
|
+
has: (a, n) => typeof n == "string" && (s(n) !== void 0 || !i && Reflect.has(a, n)),
|
|
211
|
+
ownKeys: () => i ? [...t.children.keys()] : Reflect.ownKeys(g),
|
|
212
|
+
getOwnPropertyDescriptor: (a, n) => typeof n == "string" && s(n) ? { enumerable: !0, configurable: !0 } : i ? void 0 : Reflect.getOwnPropertyDescriptor(a, n)
|
|
213
|
+
});
|
|
214
|
+
return k.set(t, m), m;
|
|
215
|
+
}
|
|
216
|
+
function P(t) {
|
|
217
|
+
if (t == null || typeof t != "object") return !1;
|
|
218
|
+
const e = t.__kind;
|
|
219
|
+
return e === "group" || e === "array";
|
|
220
|
+
}
|
|
221
|
+
function O(t) {
|
|
222
|
+
return t == null || typeof t != "object" ? !1 : t.__kind === "array";
|
|
223
|
+
}
|
|
224
|
+
function M(t) {
|
|
225
|
+
return t instanceof A || O(t);
|
|
226
|
+
}
|
|
227
|
+
function T(t, e) {
|
|
228
|
+
if (!e) return;
|
|
229
|
+
let r = t;
|
|
230
|
+
for (const i of e.split(".")) {
|
|
231
|
+
if (!r) return;
|
|
232
|
+
if (r.kind === "group") r = r.children.get(i);
|
|
233
|
+
else if (r.kind === "array") r = r.items.peek()[Number(i)];
|
|
234
|
+
else return;
|
|
235
|
+
}
|
|
236
|
+
if (r)
|
|
237
|
+
return r.kind === "leaf" ? r.signal : r.kind === "array" ? b(r) : void 0;
|
|
238
|
+
}
|
|
239
|
+
export {
|
|
240
|
+
$ as G,
|
|
241
|
+
M as a,
|
|
242
|
+
_ as b,
|
|
243
|
+
S as c,
|
|
244
|
+
O as d,
|
|
245
|
+
P as i,
|
|
246
|
+
R as m,
|
|
247
|
+
T as r,
|
|
248
|
+
b as s,
|
|
249
|
+
D as u
|
|
250
|
+
};
|
package/dist/model.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import { c as s, e as r } from "./create-model-
|
|
2
|
-
import {
|
|
3
|
-
import { c as
|
|
1
|
+
import { c as s, e as r, a as i } from "./create-model-B8U-COv-.js";
|
|
2
|
+
import { b as o, i as c, a as n, m as t, u as d } from "./model-signals-proxy-2vqS243J.js";
|
|
3
|
+
import { c as m, a as u, r as b, b as h, d as p, e as g, f as k, s as v, t as D, w as F } from "./behaviors-value-C7dSEhCc.js";
|
|
4
4
|
export {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
m as computeFrom,
|
|
6
|
+
u as copyFrom,
|
|
7
7
|
s as createModel,
|
|
8
8
|
r as eachLeafSignal,
|
|
9
|
-
i as
|
|
10
|
-
|
|
11
|
-
c as
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
i as eachValueSignal,
|
|
10
|
+
o as isDerived,
|
|
11
|
+
c as isModelContainerSignal,
|
|
12
|
+
n as isValueSignal,
|
|
13
|
+
t as markDerived,
|
|
14
|
+
b as resetWhen,
|
|
15
|
+
h as revalidateWhen,
|
|
14
16
|
p as runOutsideEffect,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
g as safeCallback,
|
|
18
|
+
k as safeDebouncedCallback,
|
|
19
|
+
v as syncFields,
|
|
20
|
+
D as transformValue,
|
|
21
|
+
d as unmarkDerived,
|
|
22
|
+
F as watchField
|
|
21
23
|
};
|
|
@@ -15,6 +15,7 @@ import { ValidationError } from '../../../form/types/index';
|
|
|
15
15
|
*
|
|
16
16
|
* function TextField({ control }: Props) {
|
|
17
17
|
* const state = useFormControl(control);
|
|
18
|
+
* const message = useValidationMessage(); // из '@reformer/core/i18n'
|
|
18
19
|
*
|
|
19
20
|
* return (
|
|
20
21
|
* <div>
|
|
@@ -24,7 +25,7 @@ import { ValidationError } from '../../../form/types/index';
|
|
|
24
25
|
* onChange={e => control.setValue(e.target.value)}
|
|
25
26
|
* />
|
|
26
27
|
* {state.shouldShowError && state.errors[0] && (
|
|
27
|
-
* <span className="error">{state.errors[0]
|
|
28
|
+
* <span className="error">{message(state.errors[0])}</span>
|
|
28
29
|
* )}
|
|
29
30
|
* </div>
|
|
30
31
|
* );
|
|
@@ -89,11 +90,12 @@ export interface FieldControlState<T> {
|
|
|
89
90
|
* @example
|
|
90
91
|
* ```tsx
|
|
91
92
|
* const { errors } = useFormControl(field);
|
|
93
|
+
* const message = useValidationMessage(); // из '@reformer/core/i18n'
|
|
92
94
|
*
|
|
93
95
|
* return (
|
|
94
96
|
* <ul className="error-list">
|
|
95
97
|
* {errors.map((error, i) => (
|
|
96
|
-
* <li key={i}>{error
|
|
98
|
+
* <li key={i}>{message(error)}</li>
|
|
97
99
|
* ))}
|
|
98
100
|
* </ul>
|
|
99
101
|
* );
|
|
@@ -152,12 +154,13 @@ export interface FieldControlState<T> {
|
|
|
152
154
|
* @example
|
|
153
155
|
* ```tsx
|
|
154
156
|
* const { shouldShowError, errors } = useFormControl(field);
|
|
157
|
+
* const message = useValidationMessage(); // из '@reformer/core/i18n'
|
|
155
158
|
*
|
|
156
159
|
* return (
|
|
157
160
|
* <div>
|
|
158
161
|
* <input {...props} />
|
|
159
162
|
* {shouldShowError && (
|
|
160
|
-
* <span className="error">{errors[0]
|
|
163
|
+
* <span className="error">{message(errors[0])}</span>
|
|
161
164
|
* )}
|
|
162
165
|
* </div>
|
|
163
166
|
* );
|
|
@@ -134,6 +134,7 @@ import { FormValue } from '../../../form/types/index';
|
|
|
134
134
|
* // Основной редактор использует useFormControl для полного состояния
|
|
135
135
|
* function MarkdownEditor({ control }: MarkdownEditorProps) {
|
|
136
136
|
* const { value, shouldShowError, errors } = useFormControl(control);
|
|
137
|
+
* const message = useValidationMessage(); // из '@reformer/core/i18n'
|
|
137
138
|
*
|
|
138
139
|
* return (
|
|
139
140
|
* <div className="editor-container">
|
|
@@ -141,7 +142,7 @@ import { FormValue } from '../../../form/types/index';
|
|
|
141
142
|
* value={value}
|
|
142
143
|
* onChange={e => control.setValue(e.target.value)}
|
|
143
144
|
* />
|
|
144
|
-
* {shouldShowError && <span className="error">{errors[0]
|
|
145
|
+
* {shouldShowError && <span className="error">{message(errors[0])}</span>}
|
|
145
146
|
*
|
|
146
147
|
* {/* Preview обновляется только при изменении value *}
|
|
147
148
|
* <MarkdownPreview control={control} />
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { I18nHandle } from '../../../i18n/translator';
|
|
2
|
+
/** Имя контекста и одновременно маркер, по которому страж ищет его копии в сборках. */
|
|
3
|
+
export declare const I18N_CONTEXT_MARKER = "ReformerI18nContext";
|
|
4
|
+
/** Что видит компонент: ручка активной локали и состояние её загрузки. */
|
|
5
|
+
export interface I18nContextValue extends I18nHandle {
|
|
6
|
+
/** Идёт загрузка другого языка; на экране пока прежний. Без загрузчика всегда `false`. */
|
|
7
|
+
readonly pending: boolean;
|
|
8
|
+
/** Ошибка последней загрузки языка. */
|
|
9
|
+
readonly error: unknown;
|
|
10
|
+
}
|
|
11
|
+
/** Значение контекста для локали: ручка плюс состояние загрузки. */
|
|
12
|
+
export declare function contextValue(handle: I18nHandle, pending: boolean, error: unknown): I18nContextValue;
|
|
13
|
+
export declare const I18nContext: import('react').Context<I18nContextValue>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ValidationError } from '../../../form/types/contracts';
|
|
2
|
+
import { Messages } from '../../../i18n/locale';
|
|
3
|
+
import { MessageValues } from '../../../i18n/message-format';
|
|
4
|
+
import { I18nContextValue } from './context';
|
|
5
|
+
/**
|
|
6
|
+
* Активная локаль: перевод ключей приложения, форматирование чисел, дат и размеров, состояние
|
|
7
|
+
* загрузки языка. Без провайдера — английский с пустым словарём.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* function LangBadge() {
|
|
12
|
+
* const { code, pending, t } = useI18n();
|
|
13
|
+
* return <span aria-busy={pending}>{t('app.language')}: {code}</span>;
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function useI18n(): I18nContextValue;
|
|
18
|
+
/**
|
|
19
|
+
* Переводчик пакета: ищет ключ в локали провайдера, а при промахе берёт встроенную английскую
|
|
20
|
+
* таблицу этого пакета. Так пакет говорит по-английски без провайдера и не зависит от того, знает
|
|
21
|
+
* ли локаль его ключи. Тип ключа выводится из таблицы — опечатка в ключе не скомпилируется.
|
|
22
|
+
*
|
|
23
|
+
* `defaults` должен быть стабильной ссылкой (импорт JSON-модуля), иначе переводчик будет
|
|
24
|
+
* пересоздаваться на каждый рендер.
|
|
25
|
+
*
|
|
26
|
+
* @param defaults - Встроенная английская таблица пакета.
|
|
27
|
+
* @returns Функция `(ключ, значения?) => строка`; её идентичность меняется вместе с локалью.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* import en from './locale/en.json';
|
|
32
|
+
*
|
|
33
|
+
* const useKitMessages = () => useMessages(en);
|
|
34
|
+
*
|
|
35
|
+
* function ClearButton() {
|
|
36
|
+
* const t = useKitMessages();
|
|
37
|
+
* return <button aria-label={t('kit.select.clear')} />;
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function useMessages<D extends Messages>(defaults: D): (key: keyof D & string, values?: MessageValues) => string;
|
|
42
|
+
/**
|
|
43
|
+
* Резолвер текста ошибки валидации по активной локали: `messageKey` автора → явное `message` →
|
|
44
|
+
* словарь локали по коду → встроенный английский → код. Идентичность функции меняется вместе с
|
|
45
|
+
* локалью, поэтому показанные ошибки переводятся при смене языка без повторной валидации.
|
|
46
|
+
*
|
|
47
|
+
* `FormField` из `@reformer/cdk` использует его сам; вызывайте напрямую, если рисуете ошибки
|
|
48
|
+
* своим компонентом.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* function FieldErrors({ control }: { control: FieldNode<string> }) {
|
|
53
|
+
* const message = useValidationMessage();
|
|
54
|
+
* const { errors } = useFormControl(control);
|
|
55
|
+
* return <>{errors.map((error) => <span key={error.code}>{message(error)}</span>)}</>;
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function useValidationMessage(): (error: ValidationError) => string;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { FormLocale } from '../../../i18n/locale';
|
|
3
|
+
import { LocaleLoad } from '../../../i18n/locale-store';
|
|
4
|
+
/** Режим «готовая локаль». */
|
|
5
|
+
export interface I18nStaticProviderProps {
|
|
6
|
+
/** Локаль. Смена объекта переключает язык сразу. */
|
|
7
|
+
locale: FormLocale;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/** Режим «провайдер грузит сам». */
|
|
11
|
+
export interface I18nLoadingProviderProps {
|
|
12
|
+
/** Код языка. Смена кода запускает загрузку; до её конца на экране прежний язык. */
|
|
13
|
+
lang: string;
|
|
14
|
+
/** Загрузчик локалей — обычно результат `createLocaleLoader`. */
|
|
15
|
+
load: LocaleLoad;
|
|
16
|
+
/**
|
|
17
|
+
* Что показать, пока не загружена самая первая локаль. По умолчанию — ничего: иначе на кадр
|
|
18
|
+
* мелькнул бы встроенный английский. Если локаль уже в кэше загрузчика (`load.preload(lang)`
|
|
19
|
+
* до монтирования), первый рендер синхронный и `fallback` не показывается.
|
|
20
|
+
*/
|
|
21
|
+
fallback?: ReactNode;
|
|
22
|
+
/** Отказ загрузки. Язык на экране при этом не меняется. */
|
|
23
|
+
onError?: (error: unknown, lang: string) => void;
|
|
24
|
+
children?: ReactNode;
|
|
25
|
+
}
|
|
26
|
+
export type I18nProviderProps = I18nStaticProviderProps | I18nLoadingProviderProps;
|
|
27
|
+
/**
|
|
28
|
+
* Провайдер локализации для подписей компонентов, ошибок валидации и авторских подписей формы.
|
|
29
|
+
* Без провайдера компоненты говорят встроенным английским.
|
|
30
|
+
*
|
|
31
|
+
* При смене `lang` на экране остаётся прежний язык, пока новый не загрузится (`useI18n().pending`
|
|
32
|
+
* — для индикатора). При быстром переключении применяется только последний запрос. Вложенный
|
|
33
|
+
* провайдер заменяет локаль для своего поддерева целиком.
|
|
34
|
+
*
|
|
35
|
+
* @example Провайдер грузит локаль сам
|
|
36
|
+
* ```tsx
|
|
37
|
+
* const [lang, setLang] = useState('ru');
|
|
38
|
+
*
|
|
39
|
+
* <I18nProvider lang={lang} load={loadLocale}>
|
|
40
|
+
* <LangSwitch value={lang} onChange={setLang} />
|
|
41
|
+
* <CreditForm />
|
|
42
|
+
* </I18nProvider>
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example Готовая локаль — SSR и тесты
|
|
46
|
+
* ```tsx
|
|
47
|
+
* import { ru } from '@reformer/ui-kit/locale/ru';
|
|
48
|
+
*
|
|
49
|
+
* <I18nProvider locale={ru}><CreditForm /></I18nProvider>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function I18nProvider(props: I18nProviderProps): ReactElement | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { signal as A, effect as M } from "@preact/signals-core";
|
|
2
|
-
import {
|
|
2
|
+
import { a as W } from "./create-model-B8U-COv-.js";
|
|
3
3
|
import { g as v } from "./signal-node-registry-tiwel-TV.js";
|
|
4
4
|
let g = null;
|
|
5
5
|
function E(e, n) {
|
|
@@ -75,23 +75,23 @@ function z(e) {
|
|
|
75
75
|
return e;
|
|
76
76
|
}
|
|
77
77
|
const x = /* @__PURE__ */ new WeakMap();
|
|
78
|
-
function
|
|
78
|
+
function P(e, n) {
|
|
79
79
|
let t = x.get(e);
|
|
80
80
|
t || x.set(e, t = /* @__PURE__ */ new WeakMap());
|
|
81
81
|
let r = t.get(n);
|
|
82
82
|
return r || t.set(n, r = { fields: /* @__PURE__ */ new Set(), ac: null }), r;
|
|
83
83
|
}
|
|
84
|
-
const
|
|
84
|
+
const T = (e) => {
|
|
85
85
|
for (const n of e.values()) for (const t of n) if (t.severity !== "warning") return !0;
|
|
86
86
|
return !1;
|
|
87
87
|
};
|
|
88
|
-
function
|
|
88
|
+
function V(e) {
|
|
89
89
|
return e.aborted ? Promise.resolve() : new Promise((n) => {
|
|
90
90
|
e.addEventListener("abort", () => n(), { once: !0 });
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
93
|
async function C(e, n, t) {
|
|
94
|
-
const r =
|
|
94
|
+
const r = P(e, n);
|
|
95
95
|
r.ac?.abort();
|
|
96
96
|
const o = new AbortController();
|
|
97
97
|
r.ac = o;
|
|
@@ -102,12 +102,12 @@ async function C(e, n, t) {
|
|
|
102
102
|
whenStack: [],
|
|
103
103
|
signal: o.signal
|
|
104
104
|
};
|
|
105
|
-
if (E(a, () => n({ model: e })), a.pending.length && await Promise.race([Promise.all(a.pending),
|
|
105
|
+
if (E(a, () => n({ model: e })), a.pending.length && await Promise.race([Promise.all(a.pending), V(o.signal)]), o.signal.aborted) return !1;
|
|
106
106
|
const i = new Set(a.errors.keys());
|
|
107
107
|
for (const s of r.fields) i.has(s) || v(s)?.setErrors([]);
|
|
108
108
|
for (const s of i) v(s)?.setErrors(a.errors.get(s) ?? []);
|
|
109
109
|
if (t?.touch) for (const s of i) v(s)?.markAsTouched();
|
|
110
|
-
return r.fields = i, !
|
|
110
|
+
return r.fields = i, !T(a.errors);
|
|
111
111
|
}
|
|
112
112
|
function G(e, n, t = {}) {
|
|
113
113
|
const { strategy: r = "submit", debounce: o = 0, liveAfterSubmit: a = "change" } = t, i = A(!1);
|
package/dist/validation.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as s, h as d, c as i, f as l, e as t, v as o, a as c, g as n, b as r } from "./strategy-
|
|
1
|
+
import { d as s, h as d, c as i, f as l, e as t, v as o, a as c, g as n, b as r } from "./strategy-BXS_gBfz.js";
|
|
2
2
|
export {
|
|
3
3
|
s as apply,
|
|
4
4
|
d as createFormValidation,
|
package/dist/validators/email.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
message: e?.message ?? "invalid",
|
|
6
|
-
params: e?.params
|
|
7
|
-
} : null;
|
|
1
|
+
import { v as n } from "../validation-error-B-U3RsV0.js";
|
|
2
|
+
const i = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3
|
+
function o(t) {
|
|
4
|
+
return (r) => r ? i.test(r) ? null : n("email", t) : null;
|
|
8
5
|
}
|
|
9
6
|
export {
|
|
10
|
-
|
|
7
|
+
o as email
|
|
11
8
|
};
|
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import { p as
|
|
2
|
-
|
|
1
|
+
import { p as e, n as i, g as l } from "../date-utils-dTT_x_Be.js";
|
|
2
|
+
import { v as u } from "../validation-error-B-U3RsV0.js";
|
|
3
|
+
function f(n) {
|
|
3
4
|
return (r) => {
|
|
4
5
|
if (r == null || r === "")
|
|
5
6
|
return null;
|
|
6
|
-
const
|
|
7
|
-
if (
|
|
7
|
+
const t = e(r);
|
|
8
|
+
if (t === null)
|
|
8
9
|
return null;
|
|
9
|
-
const
|
|
10
|
-
return
|
|
11
|
-
code: "date_past",
|
|
12
|
-
message: a?.message ?? "invalid",
|
|
13
|
-
params: a?.params
|
|
14
|
-
} : null;
|
|
10
|
+
const o = i(t), a = l();
|
|
11
|
+
return o < a ? u("date_past", n) : null;
|
|
15
12
|
};
|
|
16
13
|
}
|
|
17
14
|
export {
|
|
18
|
-
|
|
15
|
+
f as futureDate
|
|
19
16
|
};
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
message: e?.message ?? "invalid",
|
|
5
|
-
params: e?.params
|
|
6
|
-
};
|
|
1
|
+
import { v as t } from "../validation-error-B-U3RsV0.js";
|
|
2
|
+
function e(n) {
|
|
3
|
+
return (r) => r == null || typeof r != "number" || isNaN(r) || Number.isInteger(r) ? null : t("integer", n);
|
|
7
4
|
}
|
|
8
5
|
export {
|
|
9
|
-
|
|
6
|
+
e as integer
|
|
10
7
|
};
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import { p as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
message: e?.message ?? "invalid",
|
|
6
|
-
params: e?.params
|
|
7
|
-
} : null;
|
|
1
|
+
import { p as t } from "../date-utils-dTT_x_Be.js";
|
|
2
|
+
import { v as i } from "../validation-error-B-U3RsV0.js";
|
|
3
|
+
function l(n) {
|
|
4
|
+
return (r) => r == null || r === "" ? null : t(r) === null ? i("date_invalid", n) : null;
|
|
8
5
|
}
|
|
9
6
|
export {
|
|
10
|
-
|
|
7
|
+
l as isDate
|
|
11
8
|
};
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
message: e?.message ?? "invalid",
|
|
5
|
-
params: e?.params
|
|
6
|
-
} : null;
|
|
1
|
+
import { v as i } from "../validation-error-B-U3RsV0.js";
|
|
2
|
+
function o(n) {
|
|
3
|
+
return (r) => r == null ? null : typeof r != "number" || isNaN(r) ? i("isNumber", n) : null;
|
|
7
4
|
}
|
|
8
5
|
export {
|
|
9
|
-
|
|
6
|
+
o as isNumber
|
|
10
7
|
};
|