@valfuse-node/react 0.2.0
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/LICENSE +22 -0
- package/README.md +620 -0
- package/dist/index.d.mts +446 -0
- package/dist/index.d.ts +446 -0
- package/dist/index.js +986 -0
- package/dist/index.mjs +957 -0
- package/package.json +48 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,957 @@
|
|
|
1
|
+
// src/hooks/use-valfuse-form.ts
|
|
2
|
+
import { useMemo as useMemo3 } from "react";
|
|
3
|
+
|
|
4
|
+
// src/hooks/sub-hooks/use-form-core.ts
|
|
5
|
+
import { useState, useRef } from "react";
|
|
6
|
+
function useFormCore(props) {
|
|
7
|
+
const { schema, defaultValues, mode = "onSubmit" } = props;
|
|
8
|
+
const [values, setValues] = useState(
|
|
9
|
+
() => ({ ...defaultValues })
|
|
10
|
+
);
|
|
11
|
+
const [errors, setErrorsState] = useState({});
|
|
12
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
13
|
+
const [isSubmitted, setIsSubmitted] = useState(false);
|
|
14
|
+
const [isSubmitSuccessful, setIsSubmitSuccessful] = useState(false);
|
|
15
|
+
const [submitCount, setSubmitCount] = useState(0);
|
|
16
|
+
const [touchedFields, setTouchedFields] = useState(
|
|
17
|
+
() => /* @__PURE__ */ new Set()
|
|
18
|
+
);
|
|
19
|
+
const valuesRef = useRef(values);
|
|
20
|
+
valuesRef.current = values;
|
|
21
|
+
const errorsRef = useRef(errors);
|
|
22
|
+
errorsRef.current = errors;
|
|
23
|
+
const touchedFieldsRef = useRef(touchedFields);
|
|
24
|
+
touchedFieldsRef.current = touchedFields;
|
|
25
|
+
const modeRef = useRef(mode);
|
|
26
|
+
modeRef.current = mode;
|
|
27
|
+
const schemaRef = useRef(schema);
|
|
28
|
+
schemaRef.current = schema;
|
|
29
|
+
const watchSubscribersRef = useRef(/* @__PURE__ */ new Set());
|
|
30
|
+
const lastChangedFieldRef = useRef(void 0);
|
|
31
|
+
return {
|
|
32
|
+
schema,
|
|
33
|
+
defaultValues,
|
|
34
|
+
mode,
|
|
35
|
+
values,
|
|
36
|
+
errors,
|
|
37
|
+
isSubmitting,
|
|
38
|
+
isSubmitted,
|
|
39
|
+
isSubmitSuccessful,
|
|
40
|
+
submitCount,
|
|
41
|
+
touchedFields,
|
|
42
|
+
setValues,
|
|
43
|
+
setErrorsState,
|
|
44
|
+
setTouchedFields,
|
|
45
|
+
setIsSubmitting,
|
|
46
|
+
setIsSubmitted,
|
|
47
|
+
setIsSubmitSuccessful,
|
|
48
|
+
setSubmitCount,
|
|
49
|
+
refs: {
|
|
50
|
+
valuesRef,
|
|
51
|
+
errorsRef,
|
|
52
|
+
touchedFieldsRef,
|
|
53
|
+
modeRef,
|
|
54
|
+
schemaRef,
|
|
55
|
+
lastChangedFieldRef,
|
|
56
|
+
watchSubscribersRef
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/hooks/sub-hooks/use-field-validation.ts
|
|
62
|
+
import { useCallback } from "react";
|
|
63
|
+
import { validateSchema } from "@valfuse-node/form";
|
|
64
|
+
|
|
65
|
+
// src/helpers/validation-mode.ts
|
|
66
|
+
function shouldValidateOnChange(mode, isTouched) {
|
|
67
|
+
return mode === "onChange" || mode === "all" || mode === "onTouched" && isTouched;
|
|
68
|
+
}
|
|
69
|
+
function shouldValidateOnBlur(mode) {
|
|
70
|
+
return mode === "onBlur" || mode === "all" || mode === "onTouched";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/helpers/field-error.ts
|
|
74
|
+
function buildFieldError(fieldErrors, field) {
|
|
75
|
+
const err = fieldErrors[field];
|
|
76
|
+
if (!err) return null;
|
|
77
|
+
return {
|
|
78
|
+
message: err.message,
|
|
79
|
+
type: err.type ?? "validation",
|
|
80
|
+
...err.code !== void 0 && { code: err.code }
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function mapToFieldErrors(schemaErrors) {
|
|
84
|
+
return Object.fromEntries(
|
|
85
|
+
Object.entries(schemaErrors).map(([key, err]) => {
|
|
86
|
+
const fieldError = {
|
|
87
|
+
message: err.message,
|
|
88
|
+
type: err.type ?? "validation",
|
|
89
|
+
...err.code !== void 0 && { code: err.code },
|
|
90
|
+
...err.metadata !== void 0 && { metadata: err.metadata }
|
|
91
|
+
};
|
|
92
|
+
return [key, fieldError];
|
|
93
|
+
})
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/hooks/sub-hooks/use-field-validation.ts
|
|
98
|
+
function useFieldValidation({
|
|
99
|
+
schema,
|
|
100
|
+
setErrorsState
|
|
101
|
+
}) {
|
|
102
|
+
const validateField = useCallback(
|
|
103
|
+
(name, currentValues) => {
|
|
104
|
+
if (!schema[name]) return;
|
|
105
|
+
const raw = validateSchema({ [name]: schema[name] }, currentValues);
|
|
106
|
+
const error = buildFieldError(raw, name);
|
|
107
|
+
setErrorsState((prev) => {
|
|
108
|
+
if (!error && !(name in prev)) return prev;
|
|
109
|
+
const prevError = prev[name];
|
|
110
|
+
if (error && prevError && error.message === prevError.message && error.type === prevError.type && error.code === prevError.code) return prev;
|
|
111
|
+
const next = { ...prev };
|
|
112
|
+
if (error) {
|
|
113
|
+
next[name] = error;
|
|
114
|
+
} else {
|
|
115
|
+
delete next[name];
|
|
116
|
+
}
|
|
117
|
+
return next;
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
[schema, setErrorsState]
|
|
121
|
+
);
|
|
122
|
+
const clearStaleFieldError = useCallback(
|
|
123
|
+
(name) => {
|
|
124
|
+
setErrorsState((prev) => {
|
|
125
|
+
if (!(name in prev)) return prev;
|
|
126
|
+
const next = { ...prev };
|
|
127
|
+
delete next[name];
|
|
128
|
+
return next;
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
[setErrorsState]
|
|
132
|
+
);
|
|
133
|
+
return { validateField, clearStaleFieldError };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/hooks/sub-hooks/use-form-registration.ts
|
|
137
|
+
import { useCallback as useCallback2, useMemo } from "react";
|
|
138
|
+
function useFormRegistration({
|
|
139
|
+
core,
|
|
140
|
+
validateField,
|
|
141
|
+
clearStaleFieldError
|
|
142
|
+
}) {
|
|
143
|
+
const { values, refs, touchedFields, setValues, setTouchedFields } = core;
|
|
144
|
+
const valuesRef = refs.valuesRef;
|
|
145
|
+
const modeRef = refs.modeRef;
|
|
146
|
+
const schemaRef = refs.schemaRef;
|
|
147
|
+
const touchedFieldsRef = refs.touchedFieldsRef;
|
|
148
|
+
const lastChangedFieldRef = refs.lastChangedFieldRef;
|
|
149
|
+
const register = useCallback2(
|
|
150
|
+
(name) => ({
|
|
151
|
+
name,
|
|
152
|
+
value: valuesRef.current[name],
|
|
153
|
+
onChange: (e) => {
|
|
154
|
+
const rawValue = e.target.value;
|
|
155
|
+
const fieldTransform = schemaRef.current[name]?.transform;
|
|
156
|
+
const newValue = fieldTransform ? fieldTransform(rawValue) : rawValue;
|
|
157
|
+
const updated = { ...valuesRef.current, [name]: newValue };
|
|
158
|
+
lastChangedFieldRef.current = name;
|
|
159
|
+
setValues(updated);
|
|
160
|
+
if (shouldValidateOnChange(modeRef.current, touchedFieldsRef.current.has(name))) {
|
|
161
|
+
validateField(name, updated);
|
|
162
|
+
} else {
|
|
163
|
+
clearStaleFieldError(name);
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
onBlur: () => {
|
|
167
|
+
setTouchedFields((prev) => {
|
|
168
|
+
if (prev.has(name)) return prev;
|
|
169
|
+
const next = new Set(prev);
|
|
170
|
+
next.add(name);
|
|
171
|
+
return next;
|
|
172
|
+
});
|
|
173
|
+
if (shouldValidateOnBlur(modeRef.current)) {
|
|
174
|
+
const current = valuesRef.current;
|
|
175
|
+
const fieldTransform = schemaRef.current[name]?.transform;
|
|
176
|
+
const forValidation = fieldTransform ? { ...current, [name]: fieldTransform(current[name]) } : current;
|
|
177
|
+
validateField(name, forValidation);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}),
|
|
181
|
+
// mode/touchedFields/schema read via refs — only stable deps here.
|
|
182
|
+
[validateField, clearStaleFieldError]
|
|
183
|
+
);
|
|
184
|
+
const _updateField = useCallback2(
|
|
185
|
+
(name, value) => {
|
|
186
|
+
const fieldTransform = schemaRef.current[name]?.transform;
|
|
187
|
+
const transformedValue = fieldTransform ? fieldTransform(value) : value;
|
|
188
|
+
const updated = { ...valuesRef.current, [name]: transformedValue };
|
|
189
|
+
lastChangedFieldRef.current = name;
|
|
190
|
+
setValues(updated);
|
|
191
|
+
if (shouldValidateOnChange(modeRef.current, touchedFieldsRef.current.has(name))) {
|
|
192
|
+
validateField(name, updated);
|
|
193
|
+
} else {
|
|
194
|
+
clearStaleFieldError(name);
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
// schema/mode/touchedFields/values read via refs.
|
|
198
|
+
[validateField, clearStaleFieldError]
|
|
199
|
+
);
|
|
200
|
+
const _touchField = useCallback2(
|
|
201
|
+
(name) => {
|
|
202
|
+
setTouchedFields((prev) => {
|
|
203
|
+
if (prev.has(name)) return prev;
|
|
204
|
+
const next = new Set(prev);
|
|
205
|
+
next.add(name);
|
|
206
|
+
return next;
|
|
207
|
+
});
|
|
208
|
+
if (shouldValidateOnBlur(modeRef.current)) {
|
|
209
|
+
const current = valuesRef.current;
|
|
210
|
+
const fieldTransform = schemaRef.current[name]?.transform;
|
|
211
|
+
const forValidation = fieldTransform ? { ...current, [name]: fieldTransform(current[name]) } : current;
|
|
212
|
+
validateField(name, forValidation);
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
// schema/mode/values read via refs — only validateField is a dep.
|
|
216
|
+
[validateField]
|
|
217
|
+
);
|
|
218
|
+
const control = useMemo(
|
|
219
|
+
() => ({
|
|
220
|
+
_values: values,
|
|
221
|
+
_errors: core.errors,
|
|
222
|
+
_updateField,
|
|
223
|
+
_touchField,
|
|
224
|
+
_touchedFields: touchedFields
|
|
225
|
+
}),
|
|
226
|
+
[values, core.errors, touchedFields, _updateField, _touchField]
|
|
227
|
+
);
|
|
228
|
+
return { register, control, _updateField, _touchField };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/hooks/sub-hooks/use-form-watch.ts
|
|
232
|
+
import { useCallback as useCallback3, useEffect } from "react";
|
|
233
|
+
function useFormWatch(core) {
|
|
234
|
+
const { watchSubscribersRef, lastChangedFieldRef } = core.refs;
|
|
235
|
+
useEffect(() => {
|
|
236
|
+
if (watchSubscribersRef.current.size > 0) {
|
|
237
|
+
const info = {
|
|
238
|
+
name: lastChangedFieldRef.current,
|
|
239
|
+
type: lastChangedFieldRef.current ? "change" : void 0
|
|
240
|
+
};
|
|
241
|
+
watchSubscribersRef.current.forEach((cb) => cb(core.values, info));
|
|
242
|
+
}
|
|
243
|
+
lastChangedFieldRef.current = void 0;
|
|
244
|
+
}, [core.values, watchSubscribersRef, lastChangedFieldRef]);
|
|
245
|
+
const watch = useCallback3(
|
|
246
|
+
(nameOrNamesOrCallback) => {
|
|
247
|
+
const { valuesRef } = core.refs;
|
|
248
|
+
if (typeof nameOrNamesOrCallback === "function") {
|
|
249
|
+
const cb = nameOrNamesOrCallback;
|
|
250
|
+
watchSubscribersRef.current.add(cb);
|
|
251
|
+
return () => watchSubscribersRef.current.delete(cb);
|
|
252
|
+
}
|
|
253
|
+
if (Array.isArray(nameOrNamesOrCallback)) {
|
|
254
|
+
return nameOrNamesOrCallback.map(
|
|
255
|
+
(n) => valuesRef.current[n]
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
if (typeof nameOrNamesOrCallback === "string") {
|
|
259
|
+
return valuesRef.current[nameOrNamesOrCallback];
|
|
260
|
+
}
|
|
261
|
+
return valuesRef.current;
|
|
262
|
+
},
|
|
263
|
+
[core.refs, watchSubscribersRef]
|
|
264
|
+
);
|
|
265
|
+
return { watch };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// src/hooks/sub-hooks/use-form-actions.ts
|
|
269
|
+
import { useCallback as useCallback4 } from "react";
|
|
270
|
+
import {
|
|
271
|
+
validateSchema as validateSchema2,
|
|
272
|
+
normalizeError,
|
|
273
|
+
transformValues
|
|
274
|
+
} from "@valfuse-node/form";
|
|
275
|
+
function useFormActions(core, clearStaleFieldError) {
|
|
276
|
+
const handleSubmit = useCallback4(
|
|
277
|
+
(onValid) => async (e) => {
|
|
278
|
+
e?.preventDefault?.();
|
|
279
|
+
const { schema, refs } = core;
|
|
280
|
+
const currentValues = refs.valuesRef.current;
|
|
281
|
+
const transformedValues = transformValues(
|
|
282
|
+
schema,
|
|
283
|
+
currentValues
|
|
284
|
+
);
|
|
285
|
+
const schemaErrors = validateSchema2(
|
|
286
|
+
schema,
|
|
287
|
+
transformedValues
|
|
288
|
+
);
|
|
289
|
+
core.setSubmitCount((c) => c + 1);
|
|
290
|
+
core.setIsSubmitted(true);
|
|
291
|
+
if (Object.keys(schemaErrors).length > 0) {
|
|
292
|
+
core.setErrorsState(mapToFieldErrors(schemaErrors));
|
|
293
|
+
core.setIsSubmitSuccessful(false);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (Object.keys(refs.errorsRef.current).length > 0) core.setErrorsState({});
|
|
297
|
+
core.setIsSubmitting(true);
|
|
298
|
+
try {
|
|
299
|
+
await onValid(transformedValues);
|
|
300
|
+
core.setIsSubmitSuccessful(true);
|
|
301
|
+
} catch (err) {
|
|
302
|
+
core.setIsSubmitSuccessful(false);
|
|
303
|
+
throw err;
|
|
304
|
+
} finally {
|
|
305
|
+
core.setIsSubmitting(false);
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
// All read via core.* — list each stable field explicitly.
|
|
309
|
+
[
|
|
310
|
+
core.schema,
|
|
311
|
+
core.refs.valuesRef,
|
|
312
|
+
core.refs.errorsRef,
|
|
313
|
+
core.setSubmitCount,
|
|
314
|
+
core.setIsSubmitted,
|
|
315
|
+
core.setIsSubmitting,
|
|
316
|
+
core.setIsSubmitSuccessful,
|
|
317
|
+
core.setErrorsState
|
|
318
|
+
]
|
|
319
|
+
);
|
|
320
|
+
const setErrors = useCallback4(
|
|
321
|
+
(fieldErrors) => {
|
|
322
|
+
core.setErrorsState((prev) => {
|
|
323
|
+
const next = { ...prev };
|
|
324
|
+
let changed = false;
|
|
325
|
+
for (const [fieldName, rawError] of Object.entries(fieldErrors)) {
|
|
326
|
+
if (rawError === void 0) continue;
|
|
327
|
+
const normalized = normalizeError(rawError);
|
|
328
|
+
const prevFieldError = prev[fieldName];
|
|
329
|
+
if (prevFieldError && prevFieldError.message === normalized.message && prevFieldError.type === (normalized.type ?? "manual") && prevFieldError.code === normalized.code) continue;
|
|
330
|
+
next[fieldName] = {
|
|
331
|
+
message: normalized.message,
|
|
332
|
+
type: normalized.type ?? "manual",
|
|
333
|
+
...normalized.code !== void 0 && { code: normalized.code },
|
|
334
|
+
...normalized.metadata !== void 0 && {
|
|
335
|
+
metadata: normalized.metadata
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
changed = true;
|
|
339
|
+
}
|
|
340
|
+
return changed ? next : prev;
|
|
341
|
+
});
|
|
342
|
+
},
|
|
343
|
+
[core.setErrorsState]
|
|
344
|
+
);
|
|
345
|
+
const clearErrors = useCallback4(
|
|
346
|
+
(name) => {
|
|
347
|
+
if (name === void 0) {
|
|
348
|
+
if (Object.keys(core.refs.errorsRef.current).length === 0) return;
|
|
349
|
+
core.setErrorsState({});
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const fields = Array.isArray(name) ? name : [name];
|
|
353
|
+
core.setErrorsState((prev) => {
|
|
354
|
+
const toDelete = fields.filter((k) => k in prev);
|
|
355
|
+
if (toDelete.length === 0) return prev;
|
|
356
|
+
const next = { ...prev };
|
|
357
|
+
for (const n of toDelete) delete next[n];
|
|
358
|
+
return next;
|
|
359
|
+
});
|
|
360
|
+
},
|
|
361
|
+
[core.refs.errorsRef, core.setErrorsState]
|
|
362
|
+
);
|
|
363
|
+
const trigger = useCallback4(
|
|
364
|
+
(name) => {
|
|
365
|
+
const { schema, refs } = core;
|
|
366
|
+
const current = refs.valuesRef.current;
|
|
367
|
+
const transformed = transformValues(schema, current);
|
|
368
|
+
const fieldsToValidate = name === void 0 ? Object.keys(schema) : Array.isArray(name) ? name : [name];
|
|
369
|
+
let allValid = true;
|
|
370
|
+
let changed = false;
|
|
371
|
+
const prevErrors = refs.errorsRef.current;
|
|
372
|
+
const nextErrors = { ...prevErrors };
|
|
373
|
+
for (const field of fieldsToValidate) {
|
|
374
|
+
if (!schema[field]) continue;
|
|
375
|
+
const raw = validateSchema2({ [field]: schema[field] }, transformed);
|
|
376
|
+
const error = buildFieldError(raw, field);
|
|
377
|
+
if (error) {
|
|
378
|
+
allValid = false;
|
|
379
|
+
const prev = prevErrors[field];
|
|
380
|
+
if (!prev || prev.message !== error.message || prev.type !== error.type || prev.code !== error.code) {
|
|
381
|
+
changed = true;
|
|
382
|
+
}
|
|
383
|
+
nextErrors[field] = error;
|
|
384
|
+
} else {
|
|
385
|
+
if (field in nextErrors) {
|
|
386
|
+
changed = true;
|
|
387
|
+
delete nextErrors[field];
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (changed) core.setErrorsState(nextErrors);
|
|
392
|
+
return allValid;
|
|
393
|
+
},
|
|
394
|
+
[core.schema, core.refs.valuesRef, core.refs.errorsRef, core.setErrorsState]
|
|
395
|
+
);
|
|
396
|
+
const setValue = useCallback4(
|
|
397
|
+
(name, value, options) => {
|
|
398
|
+
const { schema, refs } = core;
|
|
399
|
+
const fieldTransform = refs.schemaRef.current[name]?.transform;
|
|
400
|
+
const transformedValue = fieldTransform ? fieldTransform(value) : value;
|
|
401
|
+
const updated = { ...refs.valuesRef.current, [name]: transformedValue };
|
|
402
|
+
refs.valuesRef.current = updated;
|
|
403
|
+
refs.lastChangedFieldRef.current = name;
|
|
404
|
+
core.setValues(updated);
|
|
405
|
+
if (options?.shouldValidate) {
|
|
406
|
+
const field = name;
|
|
407
|
+
if (!schema[field]) return;
|
|
408
|
+
const raw = validateSchema2(
|
|
409
|
+
{ [field]: schema[field] },
|
|
410
|
+
updated
|
|
411
|
+
);
|
|
412
|
+
const error = buildFieldError(raw, field);
|
|
413
|
+
core.setErrorsState((prev) => {
|
|
414
|
+
if (!error && !(field in prev)) return prev;
|
|
415
|
+
const prevError = prev[name];
|
|
416
|
+
if (error && prevError && error.message === prevError.message && error.type === prevError.type && error.code === prevError.code) return prev;
|
|
417
|
+
const next = { ...prev };
|
|
418
|
+
if (error) {
|
|
419
|
+
next[name] = error;
|
|
420
|
+
} else {
|
|
421
|
+
delete next[name];
|
|
422
|
+
}
|
|
423
|
+
return next;
|
|
424
|
+
});
|
|
425
|
+
} else {
|
|
426
|
+
clearStaleFieldError(name);
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
[
|
|
430
|
+
core.schema,
|
|
431
|
+
core.refs.schemaRef,
|
|
432
|
+
core.refs.valuesRef,
|
|
433
|
+
core.refs.lastChangedFieldRef,
|
|
434
|
+
core.setValues,
|
|
435
|
+
core.setErrorsState,
|
|
436
|
+
clearStaleFieldError
|
|
437
|
+
]
|
|
438
|
+
);
|
|
439
|
+
const reset = useCallback4(
|
|
440
|
+
(newValues) => {
|
|
441
|
+
core.setValues({ ...core.defaultValues, ...newValues });
|
|
442
|
+
core.setErrorsState({});
|
|
443
|
+
core.setTouchedFields(/* @__PURE__ */ new Set());
|
|
444
|
+
core.setIsSubmitted(false);
|
|
445
|
+
core.setIsSubmitSuccessful(false);
|
|
446
|
+
core.setSubmitCount(0);
|
|
447
|
+
},
|
|
448
|
+
[
|
|
449
|
+
core.defaultValues,
|
|
450
|
+
core.setValues,
|
|
451
|
+
core.setErrorsState,
|
|
452
|
+
core.setTouchedFields,
|
|
453
|
+
core.setIsSubmitted,
|
|
454
|
+
core.setIsSubmitSuccessful,
|
|
455
|
+
core.setSubmitCount
|
|
456
|
+
]
|
|
457
|
+
);
|
|
458
|
+
return { handleSubmit, setErrors, clearErrors, setValue, trigger, reset };
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// src/hooks/sub-hooks/use-form-derived-state.ts
|
|
462
|
+
import { useMemo as useMemo2 } from "react";
|
|
463
|
+
import { validateSchema as validateSchema3, transformValues as transformValues2 } from "@valfuse-node/form";
|
|
464
|
+
function useFormDerivedState(core) {
|
|
465
|
+
const { schema, defaultValues, values, errors, touchedFields } = core;
|
|
466
|
+
const isDirty = useMemo2(
|
|
467
|
+
() => Object.keys(defaultValues).some(
|
|
468
|
+
(key) => values[key] !== defaultValues[key]
|
|
469
|
+
),
|
|
470
|
+
[values, defaultValues]
|
|
471
|
+
);
|
|
472
|
+
const dirtyFields = useMemo2(
|
|
473
|
+
() => Object.keys(defaultValues).reduce(
|
|
474
|
+
(acc, key) => {
|
|
475
|
+
const k = key;
|
|
476
|
+
if (values[k] !== defaultValues[k]) acc[k] = true;
|
|
477
|
+
return acc;
|
|
478
|
+
},
|
|
479
|
+
{}
|
|
480
|
+
),
|
|
481
|
+
[values, defaultValues]
|
|
482
|
+
);
|
|
483
|
+
const touchedFieldsRecord = useMemo2(
|
|
484
|
+
() => Array.from(touchedFields).reduce(
|
|
485
|
+
(acc, key) => {
|
|
486
|
+
acc[key] = true;
|
|
487
|
+
return acc;
|
|
488
|
+
},
|
|
489
|
+
{}
|
|
490
|
+
),
|
|
491
|
+
[touchedFields]
|
|
492
|
+
);
|
|
493
|
+
const isValid = useMemo2(() => {
|
|
494
|
+
if (Object.keys(errors).length > 0) return false;
|
|
495
|
+
const transformed = transformValues2(
|
|
496
|
+
schema,
|
|
497
|
+
values
|
|
498
|
+
);
|
|
499
|
+
return Object.keys(validateSchema3(schema, transformed)).length === 0;
|
|
500
|
+
}, [schema, values, errors]);
|
|
501
|
+
return { isDirty, dirtyFields, touchedFieldsRecord, isValid };
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// src/hooks/use-valfuse-form.ts
|
|
505
|
+
function useValfuseForm(props) {
|
|
506
|
+
const { defaultValues } = props;
|
|
507
|
+
const core = useFormCore(props);
|
|
508
|
+
const { validateField, clearStaleFieldError } = useFieldValidation({
|
|
509
|
+
schema: core.schema,
|
|
510
|
+
setErrorsState: core.setErrorsState
|
|
511
|
+
});
|
|
512
|
+
const { register, control } = useFormRegistration({
|
|
513
|
+
core,
|
|
514
|
+
validateField,
|
|
515
|
+
clearStaleFieldError
|
|
516
|
+
});
|
|
517
|
+
const { watch } = useFormWatch(core);
|
|
518
|
+
const { handleSubmit, setErrors, clearErrors, setValue, trigger, reset } = useFormActions(core, clearStaleFieldError);
|
|
519
|
+
const { isDirty, dirtyFields, touchedFieldsRecord, isValid } = useFormDerivedState(core);
|
|
520
|
+
const formState = useMemo3(
|
|
521
|
+
() => ({
|
|
522
|
+
errors: core.errors,
|
|
523
|
+
isSubmitting: core.isSubmitting,
|
|
524
|
+
isSubmitted: core.isSubmitted,
|
|
525
|
+
isSubmitSuccessful: core.isSubmitSuccessful,
|
|
526
|
+
submitCount: core.submitCount,
|
|
527
|
+
isDirty,
|
|
528
|
+
isValid,
|
|
529
|
+
dirtyFields,
|
|
530
|
+
touchedFields: touchedFieldsRecord,
|
|
531
|
+
defaultValues
|
|
532
|
+
}),
|
|
533
|
+
[
|
|
534
|
+
core.errors,
|
|
535
|
+
core.isSubmitting,
|
|
536
|
+
core.isSubmitted,
|
|
537
|
+
core.isSubmitSuccessful,
|
|
538
|
+
core.submitCount,
|
|
539
|
+
isDirty,
|
|
540
|
+
isValid,
|
|
541
|
+
dirtyFields,
|
|
542
|
+
touchedFieldsRecord,
|
|
543
|
+
defaultValues
|
|
544
|
+
]
|
|
545
|
+
);
|
|
546
|
+
return {
|
|
547
|
+
register,
|
|
548
|
+
control,
|
|
549
|
+
handleSubmit,
|
|
550
|
+
formState,
|
|
551
|
+
setErrors,
|
|
552
|
+
clearErrors,
|
|
553
|
+
setValue,
|
|
554
|
+
trigger,
|
|
555
|
+
watch,
|
|
556
|
+
reset
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/components/valfuse-controller.tsx
|
|
561
|
+
import { useCallback as useCallback5, useMemo as useMemo4 } from "react";
|
|
562
|
+
function ValfuseController({
|
|
563
|
+
control,
|
|
564
|
+
name,
|
|
565
|
+
render
|
|
566
|
+
}) {
|
|
567
|
+
const onChange = useCallback5(
|
|
568
|
+
(value) => control._updateField(name, value),
|
|
569
|
+
[control._updateField, name]
|
|
570
|
+
);
|
|
571
|
+
const onBlur = useCallback5(
|
|
572
|
+
() => control._touchField(name),
|
|
573
|
+
[control._touchField, name]
|
|
574
|
+
);
|
|
575
|
+
const fieldValue = control._values[name];
|
|
576
|
+
const fieldError = control._errors[name];
|
|
577
|
+
const isTouched = control._touchedFields.has(name);
|
|
578
|
+
const field = useMemo4(
|
|
579
|
+
() => ({
|
|
580
|
+
name,
|
|
581
|
+
value: fieldValue,
|
|
582
|
+
onChange,
|
|
583
|
+
onBlur
|
|
584
|
+
}),
|
|
585
|
+
[name, fieldValue, onChange, onBlur]
|
|
586
|
+
);
|
|
587
|
+
const fieldState = useMemo4(
|
|
588
|
+
() => ({
|
|
589
|
+
error: fieldError,
|
|
590
|
+
isTouched
|
|
591
|
+
}),
|
|
592
|
+
[fieldError, isTouched]
|
|
593
|
+
);
|
|
594
|
+
return render({ field, fieldState });
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// src/localization/provider/localization-provider.tsx
|
|
598
|
+
import { createContext, useCallback as useCallback6, useMemo as useMemo5, useState as useState2 } from "react";
|
|
599
|
+
|
|
600
|
+
// src/localization/bridge/create-localization-store.ts
|
|
601
|
+
import { interpolate, lookupMessage } from "@valfuse-node/localization/runtime";
|
|
602
|
+
function createLocalizationStore(manifest, initialLocale) {
|
|
603
|
+
let locale = initialLocale ?? manifest.base_locale;
|
|
604
|
+
return {
|
|
605
|
+
getLocale: () => locale,
|
|
606
|
+
setLocale(nextLocale) {
|
|
607
|
+
locale = nextLocale;
|
|
608
|
+
},
|
|
609
|
+
t(key, params) {
|
|
610
|
+
const value = lookupMessage(
|
|
611
|
+
{
|
|
612
|
+
locale,
|
|
613
|
+
fallbackLocale: manifest.fallback_locale,
|
|
614
|
+
messages: manifest.messages
|
|
615
|
+
},
|
|
616
|
+
key
|
|
617
|
+
);
|
|
618
|
+
return interpolate(value, params);
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// src/localization/provider/localization-provider.tsx
|
|
624
|
+
import { jsx } from "react/jsx-runtime";
|
|
625
|
+
var LocalizationContext = createContext(null);
|
|
626
|
+
function determineInitialLocale(manifest, initialLocale, storage) {
|
|
627
|
+
const stored = storage?.get();
|
|
628
|
+
if (stored && manifest.locales.includes(stored)) return stored;
|
|
629
|
+
if (initialLocale && manifest.locales.includes(initialLocale)) return initialLocale;
|
|
630
|
+
return manifest.base_locale;
|
|
631
|
+
}
|
|
632
|
+
function LocalizationProvider({
|
|
633
|
+
manifest,
|
|
634
|
+
initialLocale,
|
|
635
|
+
storage,
|
|
636
|
+
children
|
|
637
|
+
}) {
|
|
638
|
+
const [locale, _setLocale] = useState2(
|
|
639
|
+
() => determineInitialLocale(manifest, initialLocale, storage)
|
|
640
|
+
);
|
|
641
|
+
const setLocale = useCallback6(
|
|
642
|
+
(nextLocale) => {
|
|
643
|
+
storage?.set(nextLocale);
|
|
644
|
+
_setLocale(nextLocale);
|
|
645
|
+
},
|
|
646
|
+
[storage]
|
|
647
|
+
);
|
|
648
|
+
const value = useMemo5(() => {
|
|
649
|
+
const store = createLocalizationStore(manifest, locale);
|
|
650
|
+
return { locale, setLocale, store, manifest };
|
|
651
|
+
}, [locale, manifest, setLocale]);
|
|
652
|
+
return /* @__PURE__ */ jsx(LocalizationContext.Provider, { value, children });
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// src/localization/hooks/use-localization.ts
|
|
656
|
+
import { useCallback as useCallback7, useContext, useMemo as useMemo6 } from "react";
|
|
657
|
+
import {
|
|
658
|
+
interpolate as interpolate2,
|
|
659
|
+
lookupMessage as lookupMessage2,
|
|
660
|
+
pickStructuredContextVariant,
|
|
661
|
+
pickStructuredGenderVariant,
|
|
662
|
+
pickStructuredPluralVariant
|
|
663
|
+
} from "@valfuse-node/localization/runtime";
|
|
664
|
+
function pickFallbackText(fallback, key) {
|
|
665
|
+
if (!fallback) return void 0;
|
|
666
|
+
if (typeof fallback === "string") return fallback;
|
|
667
|
+
if (typeof fallback === "function") return fallback(key);
|
|
668
|
+
return fallback[key];
|
|
669
|
+
}
|
|
670
|
+
function useLocalization(options = {}) {
|
|
671
|
+
const context = useContext(LocalizationContext);
|
|
672
|
+
if (!context) {
|
|
673
|
+
throw new Error("useLocalization must be used within LocalizationProvider.");
|
|
674
|
+
}
|
|
675
|
+
const { locale, manifest } = context;
|
|
676
|
+
const fallback = options.fallback;
|
|
677
|
+
const runtimeContext = useMemo6(
|
|
678
|
+
() => ({
|
|
679
|
+
locale,
|
|
680
|
+
fallbackLocale: manifest.fallback_locale,
|
|
681
|
+
messages: manifest.messages
|
|
682
|
+
}),
|
|
683
|
+
[locale, manifest.fallback_locale, manifest.messages]
|
|
684
|
+
);
|
|
685
|
+
const readTranslation = useCallback7(
|
|
686
|
+
(key) => lookupMessage2(runtimeContext, key),
|
|
687
|
+
[runtimeContext]
|
|
688
|
+
);
|
|
689
|
+
const hasKey = useCallback7(
|
|
690
|
+
(key) => key in (manifest.messages[locale] ?? {}) || key in (manifest.messages[manifest.fallback_locale] ?? {}),
|
|
691
|
+
[locale, manifest.fallback_locale, manifest.messages]
|
|
692
|
+
);
|
|
693
|
+
const translate = useCallback7(
|
|
694
|
+
(key, fallbackValue) => {
|
|
695
|
+
const translated = readTranslation(key);
|
|
696
|
+
if (!translated || translated === key) {
|
|
697
|
+
if (fallbackValue === null) return translated;
|
|
698
|
+
return fallbackValue ?? pickFallbackText(fallback, key) ?? translated;
|
|
699
|
+
}
|
|
700
|
+
return translated;
|
|
701
|
+
},
|
|
702
|
+
[fallback, readTranslation]
|
|
703
|
+
);
|
|
704
|
+
const format = useCallback7(
|
|
705
|
+
(key, params) => interpolate2(translate(key), params),
|
|
706
|
+
[translate]
|
|
707
|
+
);
|
|
708
|
+
const translateOrNull = useCallback7(
|
|
709
|
+
(key) => {
|
|
710
|
+
if (key == null) return null;
|
|
711
|
+
return hasKey(key) ? translate(key) : null;
|
|
712
|
+
},
|
|
713
|
+
[hasKey, translate]
|
|
714
|
+
);
|
|
715
|
+
const formatOrNull = useCallback7(
|
|
716
|
+
(key, params) => {
|
|
717
|
+
if (key == null) return null;
|
|
718
|
+
return hasKey(key) ? format(key, params) : null;
|
|
719
|
+
},
|
|
720
|
+
[hasKey, format]
|
|
721
|
+
);
|
|
722
|
+
const raw = useCallback7(
|
|
723
|
+
(key) => manifest.messages[locale]?.[key] ?? manifest.messages[manifest.fallback_locale]?.[key] ?? "",
|
|
724
|
+
[locale, manifest.fallback_locale, manifest.messages]
|
|
725
|
+
);
|
|
726
|
+
const plural = useCallback7(
|
|
727
|
+
(key, count) => pickStructuredPluralVariant(raw(key), count),
|
|
728
|
+
[raw]
|
|
729
|
+
);
|
|
730
|
+
const pluralOrNull = useCallback7(
|
|
731
|
+
(key, count) => {
|
|
732
|
+
if (key == null) return null;
|
|
733
|
+
return hasKey(key) ? plural(key, count) : null;
|
|
734
|
+
},
|
|
735
|
+
[hasKey, plural]
|
|
736
|
+
);
|
|
737
|
+
const gender = useCallback7(
|
|
738
|
+
(key, value, params) => interpolate2(pickStructuredGenderVariant(raw(key), value), params),
|
|
739
|
+
[raw]
|
|
740
|
+
);
|
|
741
|
+
const contextFn = useCallback7(
|
|
742
|
+
(key, value, params) => {
|
|
743
|
+
const translated = pickStructuredContextVariant(raw(key), value);
|
|
744
|
+
return params ? interpolate2(translated, params) : translated;
|
|
745
|
+
},
|
|
746
|
+
[raw]
|
|
747
|
+
);
|
|
748
|
+
const namespace = useCallback7(
|
|
749
|
+
(scope) => ({
|
|
750
|
+
translate: (key, fallbackValue) => translate(`${scope}.${key}`, fallbackValue),
|
|
751
|
+
translateOrNull: (key) => key == null ? null : translateOrNull(`${scope}.${key}`),
|
|
752
|
+
format: (key, params) => format(`${scope}.${key}`, params),
|
|
753
|
+
formatOrNull: (key, params) => key == null ? null : formatOrNull(`${scope}.${key}`, params),
|
|
754
|
+
plural: (key, count) => plural(`${scope}.${key}`, count),
|
|
755
|
+
pluralOrNull: (key, count) => key == null ? null : pluralOrNull(`${scope}.${key}`, count),
|
|
756
|
+
gender: (key, value, params) => gender(`${scope}.${key}`, value, params),
|
|
757
|
+
context: (key, value, params) => contextFn(`${scope}.${key}`, value, params)
|
|
758
|
+
}),
|
|
759
|
+
[translate, translateOrNull, format, formatOrNull, plural, pluralOrNull, gender, contextFn]
|
|
760
|
+
);
|
|
761
|
+
const entriesForLocale = useMemo6(
|
|
762
|
+
() => Object.entries(manifest.messages[locale] ?? {}).sort(
|
|
763
|
+
([a], [b]) => a.localeCompare(b)
|
|
764
|
+
),
|
|
765
|
+
[locale, manifest.messages]
|
|
766
|
+
);
|
|
767
|
+
return {
|
|
768
|
+
...context,
|
|
769
|
+
translate,
|
|
770
|
+
translateOrNull,
|
|
771
|
+
format,
|
|
772
|
+
formatOrNull,
|
|
773
|
+
plural,
|
|
774
|
+
pluralOrNull,
|
|
775
|
+
gender,
|
|
776
|
+
context: contextFn,
|
|
777
|
+
namespace,
|
|
778
|
+
entriesForLocale
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// src/localization/hooks/use-localization-tree.ts
|
|
783
|
+
import { useMemo as useMemo7 } from "react";
|
|
784
|
+
function toSegments(key) {
|
|
785
|
+
return key.split(".").slice(1);
|
|
786
|
+
}
|
|
787
|
+
function useLocalizationTree() {
|
|
788
|
+
const { store, manifest } = useLocalization();
|
|
789
|
+
return useMemo7(() => {
|
|
790
|
+
const strings = {};
|
|
791
|
+
const placeholders = {};
|
|
792
|
+
for (const entry of manifest.entries) {
|
|
793
|
+
const segments = toSegments(entry.key);
|
|
794
|
+
if (segments.length === 0) continue;
|
|
795
|
+
const target = entry.placeholders.length > 0 ? placeholders : strings;
|
|
796
|
+
let cursor = target;
|
|
797
|
+
for (let i = 0; i < segments.length - 1; i += 1) {
|
|
798
|
+
const segment = segments[i];
|
|
799
|
+
if (!segment) continue;
|
|
800
|
+
cursor[segment] ?? (cursor[segment] = {});
|
|
801
|
+
cursor = cursor[segment];
|
|
802
|
+
}
|
|
803
|
+
const leaf = segments[segments.length - 1];
|
|
804
|
+
if (!leaf) continue;
|
|
805
|
+
if (entry.placeholders.length > 0) {
|
|
806
|
+
cursor[leaf] = (params) => store.t(entry.key, params);
|
|
807
|
+
} else {
|
|
808
|
+
cursor[leaf] = store.t(entry.key);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return { strings, placeholders };
|
|
812
|
+
}, [store, manifest]);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// src/localization/lazy/create-lazy-locale-loader.ts
|
|
816
|
+
function createLazyLocaleLoader(manifest) {
|
|
817
|
+
return async (locale) => manifest.messages[locale] ?? {};
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// src/localization/ssr/create-ssr-localization-state.ts
|
|
821
|
+
function createSsrLocalizationState(manifest, locale) {
|
|
822
|
+
const activeLocale = locale ?? manifest.base_locale;
|
|
823
|
+
return {
|
|
824
|
+
locale: activeLocale,
|
|
825
|
+
messages: manifest.messages[activeLocale] ?? {}
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// src/localization/storage/locale-storage.ts
|
|
830
|
+
function localStorageStrategy(options = {}) {
|
|
831
|
+
const key = options.key ?? "locale";
|
|
832
|
+
return {
|
|
833
|
+
get() {
|
|
834
|
+
try {
|
|
835
|
+
return window.localStorage.getItem(key) ?? void 0;
|
|
836
|
+
} catch {
|
|
837
|
+
return void 0;
|
|
838
|
+
}
|
|
839
|
+
},
|
|
840
|
+
set(locale) {
|
|
841
|
+
try {
|
|
842
|
+
window.localStorage.setItem(key, locale);
|
|
843
|
+
} catch {
|
|
844
|
+
}
|
|
845
|
+
},
|
|
846
|
+
remove() {
|
|
847
|
+
try {
|
|
848
|
+
window.localStorage.removeItem(key);
|
|
849
|
+
} catch {
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
function sessionStorageStrategy(options = {}) {
|
|
855
|
+
const key = options.key ?? "locale";
|
|
856
|
+
return {
|
|
857
|
+
get() {
|
|
858
|
+
try {
|
|
859
|
+
return window.sessionStorage.getItem(key) ?? void 0;
|
|
860
|
+
} catch {
|
|
861
|
+
return void 0;
|
|
862
|
+
}
|
|
863
|
+
},
|
|
864
|
+
set(locale) {
|
|
865
|
+
try {
|
|
866
|
+
window.sessionStorage.setItem(key, locale);
|
|
867
|
+
} catch {
|
|
868
|
+
}
|
|
869
|
+
},
|
|
870
|
+
remove() {
|
|
871
|
+
try {
|
|
872
|
+
window.sessionStorage.removeItem(key);
|
|
873
|
+
} catch {
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
function cookieStrategy(options = {}) {
|
|
879
|
+
const {
|
|
880
|
+
key = "locale",
|
|
881
|
+
domain,
|
|
882
|
+
path = "/",
|
|
883
|
+
maxAge = 31536e3,
|
|
884
|
+
sameSite = "Lax"
|
|
885
|
+
} = options;
|
|
886
|
+
function buildCookie(value, age) {
|
|
887
|
+
const isSecure = options.secure !== void 0 ? options.secure : typeof location !== "undefined" && location.protocol === "https:";
|
|
888
|
+
let cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
|
889
|
+
cookie += `; path=${path}`;
|
|
890
|
+
cookie += `; max-age=${age}`;
|
|
891
|
+
if (domain) cookie += `; domain=${domain}`;
|
|
892
|
+
if (isSecure) cookie += "; Secure";
|
|
893
|
+
cookie += `; SameSite=${sameSite}`;
|
|
894
|
+
return cookie;
|
|
895
|
+
}
|
|
896
|
+
return {
|
|
897
|
+
get() {
|
|
898
|
+
if (typeof document === "undefined") return void 0;
|
|
899
|
+
const encodedKey = encodeURIComponent(key);
|
|
900
|
+
const match = document.cookie.split("; ").find((c) => c.startsWith(`${encodedKey}=`));
|
|
901
|
+
const rawValue = match?.split("=").slice(1).join("=");
|
|
902
|
+
return rawValue !== void 0 ? decodeURIComponent(rawValue) : void 0;
|
|
903
|
+
},
|
|
904
|
+
set(locale) {
|
|
905
|
+
if (typeof document === "undefined") return;
|
|
906
|
+
document.cookie = buildCookie(locale, maxAge);
|
|
907
|
+
},
|
|
908
|
+
remove() {
|
|
909
|
+
if (typeof document === "undefined") return;
|
|
910
|
+
document.cookie = buildCookie("", 0);
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
function memoryStrategy(options = {}) {
|
|
915
|
+
let stored = options.initialLocale;
|
|
916
|
+
return {
|
|
917
|
+
get: () => stored,
|
|
918
|
+
set: (locale) => {
|
|
919
|
+
stored = locale;
|
|
920
|
+
},
|
|
921
|
+
remove: () => {
|
|
922
|
+
stored = void 0;
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
function composeStorage(...storages) {
|
|
927
|
+
return {
|
|
928
|
+
get() {
|
|
929
|
+
for (const s of storages) {
|
|
930
|
+
const v = s.get();
|
|
931
|
+
if (v !== void 0) return v;
|
|
932
|
+
}
|
|
933
|
+
return void 0;
|
|
934
|
+
},
|
|
935
|
+
set(locale) {
|
|
936
|
+
storages.forEach((s) => s.set(locale));
|
|
937
|
+
},
|
|
938
|
+
remove() {
|
|
939
|
+
storages.forEach((s) => s.remove?.());
|
|
940
|
+
}
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
export {
|
|
944
|
+
LocalizationProvider,
|
|
945
|
+
ValfuseController,
|
|
946
|
+
composeStorage,
|
|
947
|
+
cookieStrategy,
|
|
948
|
+
createLazyLocaleLoader,
|
|
949
|
+
createLocalizationStore,
|
|
950
|
+
createSsrLocalizationState,
|
|
951
|
+
localStorageStrategy,
|
|
952
|
+
memoryStrategy,
|
|
953
|
+
sessionStorageStrategy,
|
|
954
|
+
useLocalization,
|
|
955
|
+
useLocalizationTree,
|
|
956
|
+
useValfuseForm
|
|
957
|
+
};
|