@reformer/core 1.0.0-beta.1
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 +21 -0
- package/README.md +143 -0
- package/dist/behaviors/compute-from.d.ts +2 -0
- package/dist/behaviors/compute-from.js +31 -0
- package/dist/behaviors/copy-from.d.ts +2 -0
- package/dist/behaviors/copy-from.js +29 -0
- package/dist/behaviors/enable-when.d.ts +2 -0
- package/dist/behaviors/enable-when.js +25 -0
- package/dist/behaviors/reset-when.d.ts +2 -0
- package/dist/behaviors/reset-when.js +24 -0
- package/dist/behaviors/revalidate-when.d.ts +2 -0
- package/dist/behaviors/revalidate-when.js +18 -0
- package/dist/behaviors/sync-fields.d.ts +2 -0
- package/dist/behaviors/sync-fields.js +41 -0
- package/dist/behaviors/transform-value.d.ts +2 -0
- package/dist/behaviors/transform-value.js +45 -0
- package/dist/behaviors/watch-field.d.ts +2 -0
- package/dist/behaviors/watch-field.js +21 -0
- package/dist/behaviors.d.ts +6 -0
- package/dist/behaviors.js +29 -0
- package/dist/core/behavior/behavior-context.d.ts +47 -0
- package/dist/core/behavior/behavior-registry.d.ts +85 -0
- package/dist/core/behavior/behaviors/compute-from.d.ts +70 -0
- package/dist/core/behavior/behaviors/copy-from.d.ts +56 -0
- package/dist/core/behavior/behaviors/enable-when.d.ts +118 -0
- package/dist/core/behavior/behaviors/index.d.ts +11 -0
- package/dist/core/behavior/behaviors/reset-when.d.ts +64 -0
- package/dist/core/behavior/behaviors/revalidate-when.d.ts +53 -0
- package/dist/core/behavior/behaviors/sync-fields.d.ts +48 -0
- package/dist/core/behavior/behaviors/transform-value.d.ts +192 -0
- package/dist/core/behavior/behaviors/watch-field.d.ts +80 -0
- package/dist/core/behavior/compose-behavior.d.ts +96 -0
- package/dist/core/behavior/index.d.ts +11 -0
- package/dist/core/behavior/types.d.ts +146 -0
- package/dist/core/factories/index.d.ts +6 -0
- package/dist/core/factories/node-factory.d.ts +186 -0
- package/dist/core/nodes/array-node.d.ts +328 -0
- package/dist/core/nodes/field-node.d.ts +294 -0
- package/dist/core/nodes/form-node.d.ts +340 -0
- package/dist/core/nodes/group-node.d.ts +319 -0
- package/dist/core/types/deep-schema.d.ts +68 -0
- package/dist/core/types/field-path.d.ts +42 -0
- package/dist/core/types/form-context.d.ts +89 -0
- package/dist/core/types/form-proxy.d.ts +105 -0
- package/dist/core/types/index.d.ts +209 -0
- package/dist/core/types/validation-schema.d.ts +95 -0
- package/dist/core/utils/abstract-registry.d.ts +74 -0
- package/dist/core/utils/aggregate-signals.d.ts +71 -0
- package/dist/core/utils/create-form.d.ts +44 -0
- package/dist/core/utils/error-handler.d.ts +163 -0
- package/dist/core/utils/field-path-navigator.d.ts +240 -0
- package/dist/core/utils/field-path.d.ts +60 -0
- package/dist/core/utils/form-observer.d.ts +176 -0
- package/dist/core/utils/form-proxy-builder.d.ts +25 -0
- package/dist/core/utils/form-submitter.d.ts +121 -0
- package/dist/core/utils/index.d.ts +22 -0
- package/dist/core/utils/registry-helpers.d.ts +43 -0
- package/dist/core/utils/registry-stack.d.ts +69 -0
- package/dist/core/utils/safe-effect.d.ts +73 -0
- package/dist/core/utils/status-machine.d.ts +153 -0
- package/dist/core/utils/subscription-manager.d.ts +180 -0
- package/dist/core/utils/type-guards.d.ts +98 -0
- package/dist/core/utils/unique-id.d.ts +53 -0
- package/dist/core/validation/core/apply-when.d.ts +22 -0
- package/dist/core/validation/core/apply.d.ts +52 -0
- package/dist/core/validation/core/index.d.ts +8 -0
- package/dist/core/validation/core/validate-async.d.ts +36 -0
- package/dist/core/validation/core/validate-tree.d.ts +35 -0
- package/dist/core/validation/core/validate.d.ts +26 -0
- package/dist/core/validation/index.d.ts +27 -0
- package/dist/core/validation/validate-form.d.ts +48 -0
- package/dist/core/validation/validation-applicator.d.ts +70 -0
- package/dist/core/validation/validation-context.d.ts +86 -0
- package/dist/core/validation/validation-registry.d.ts +142 -0
- package/dist/core/validation/validators/array-validators.d.ts +53 -0
- package/dist/core/validation/validators/date-utils.d.ts +26 -0
- package/dist/core/validation/validators/email.d.ts +37 -0
- package/dist/core/validation/validators/future-date.d.ts +35 -0
- package/dist/core/validation/validators/index.d.ts +20 -0
- package/dist/core/validation/validators/is-date.d.ts +36 -0
- package/dist/core/validation/validators/max-age.d.ts +36 -0
- package/dist/core/validation/validators/max-date.d.ts +36 -0
- package/dist/core/validation/validators/max-length.d.ts +38 -0
- package/dist/core/validation/validators/max.d.ts +38 -0
- package/dist/core/validation/validators/min-age.d.ts +36 -0
- package/dist/core/validation/validators/min-date.d.ts +36 -0
- package/dist/core/validation/validators/min-length.d.ts +38 -0
- package/dist/core/validation/validators/min.d.ts +38 -0
- package/dist/core/validation/validators/number.d.ts +31 -0
- package/dist/core/validation/validators/past-date.d.ts +35 -0
- package/dist/core/validation/validators/pattern.d.ts +40 -0
- package/dist/core/validation/validators/phone.d.ts +27 -0
- package/dist/core/validation/validators/required.d.ts +41 -0
- package/dist/core/validation/validators/url.d.ts +22 -0
- package/dist/date-utils-xUWFslTj.js +29 -0
- package/dist/field-path-DuKdGcIE.js +66 -0
- package/dist/hooks/types.d.ts +328 -0
- package/dist/hooks/useArrayLength.d.ts +31 -0
- package/dist/hooks/useFormControl.d.ts +24 -0
- package/dist/hooks/useFormControlValue.d.ts +167 -0
- package/dist/hooks/useHiddenCondition.d.ts +25 -0
- package/dist/hooks/useSignalSubscription.d.ts +17 -0
- package/dist/index-D25LsbRm.js +73 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +3271 -0
- package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
- package/dist/safe-effect-Dh8uw81c.js +20 -0
- package/dist/validate-C3XiA_zf.js +10 -0
- package/dist/validators/email.d.ts +2 -0
- package/dist/validators/email.js +13 -0
- package/dist/validators/future-date.d.ts +2 -0
- package/dist/validators/future-date.js +20 -0
- package/dist/validators/is-date.d.ts +2 -0
- package/dist/validators/is-date.js +12 -0
- package/dist/validators/max-age.d.ts +2 -0
- package/dist/validators/max-age.js +20 -0
- package/dist/validators/max-date.d.ts +2 -0
- package/dist/validators/max-date.js +20 -0
- package/dist/validators/max-length.d.ts +2 -0
- package/dist/validators/max-length.js +11 -0
- package/dist/validators/max.d.ts +2 -0
- package/dist/validators/max.js +11 -0
- package/dist/validators/min-age.d.ts +2 -0
- package/dist/validators/min-age.js +20 -0
- package/dist/validators/min-date.d.ts +2 -0
- package/dist/validators/min-date.js +20 -0
- package/dist/validators/min-length.d.ts +2 -0
- package/dist/validators/min-length.js +11 -0
- package/dist/validators/min.d.ts +2 -0
- package/dist/validators/min.js +11 -0
- package/dist/validators/number.d.ts +2 -0
- package/dist/validators/number.js +35 -0
- package/dist/validators/past-date.d.ts +2 -0
- package/dist/validators/past-date.js +20 -0
- package/dist/validators/pattern.d.ts +2 -0
- package/dist/validators/pattern.js +11 -0
- package/dist/validators/phone.d.ts +2 -0
- package/dist/validators/phone.js +35 -0
- package/dist/validators/required.d.ts +2 -0
- package/dist/validators/required.js +15 -0
- package/dist/validators/url.d.ts +2 -0
- package/dist/validators/url.js +19 -0
- package/dist/validators-BGsNOgT1.js +207 -0
- package/dist/validators.d.ts +6 -0
- package/dist/validators.js +56 -0
- package/llms.txt +9351 -0
- package/package.json +166 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Alexandr Bukhtatyy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# @reformer/core
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@reformer/core)
|
|
4
|
+
[](https://www.npmjs.com/package/@reformer/core)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
Reactive form state management library for React with signals-based architecture.
|
|
8
|
+
|
|
9
|
+
## Playground
|
|
10
|
+
|
|
11
|
+
[](https://stackblitz.com/~/github.com/AlexandrBukhtatyy/ReFormer/tree/main/projects/react-playground?file=projects/react-playground/src/App.tsx)
|
|
12
|
+
|
|
13
|
+
## Documentation
|
|
14
|
+
|
|
15
|
+
Full documentation is available at [https://alexandrbukhtatyy.github.io/ReFormer/](https://alexandrbukhtatyy.github.io/ReFormer/)
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- Signals-based reactive state management
|
|
20
|
+
- Declarative form validation
|
|
21
|
+
- Dynamic form behaviors
|
|
22
|
+
- TypeScript support
|
|
23
|
+
- Tree-shakeable exports
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @reformer/core@beta # Active development is underway, so you can try beta
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
import { useMemo } from 'react';
|
|
35
|
+
import {
|
|
36
|
+
createForm,
|
|
37
|
+
useFormControl,
|
|
38
|
+
required,
|
|
39
|
+
email,
|
|
40
|
+
validate,
|
|
41
|
+
watchField,
|
|
42
|
+
FieldNode,
|
|
43
|
+
} from '@reformer/core';
|
|
44
|
+
|
|
45
|
+
// 0. Simple FormField component
|
|
46
|
+
function FormField({ label, control }: { label: string; control: FieldNode<string> }) {
|
|
47
|
+
const { value, errors } = useFormControl(control);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div>
|
|
51
|
+
<label>{label}</label>
|
|
52
|
+
<input
|
|
53
|
+
value={value}
|
|
54
|
+
onChange={(e) => control.setValue(e.target.value)}
|
|
55
|
+
onBlur={() => control.markAsTouched()}
|
|
56
|
+
/>
|
|
57
|
+
{errors.length > 0 && <span className="error">{errors[0].message}</span>}
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 1. Define form interface
|
|
63
|
+
interface RegistrationForm {
|
|
64
|
+
username: string;
|
|
65
|
+
email: string;
|
|
66
|
+
password: string;
|
|
67
|
+
confirmPassword: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 2. Form schema
|
|
71
|
+
const formSchema = {
|
|
72
|
+
username: { value: '' },
|
|
73
|
+
email: { value: '' },
|
|
74
|
+
password: { value: '' },
|
|
75
|
+
confirmPassword: { value: '' },
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// 3. Validation schema
|
|
79
|
+
validationSchema = (path) => {
|
|
80
|
+
required(path.username);
|
|
81
|
+
|
|
82
|
+
required(path.email);
|
|
83
|
+
email(path.email);
|
|
84
|
+
|
|
85
|
+
required(path.password);
|
|
86
|
+
required(path.confirmPassword);
|
|
87
|
+
|
|
88
|
+
// Cross-field validation: passwords must match
|
|
89
|
+
validate(path.confirmPassword, (value, ctx) => {
|
|
90
|
+
const password = ctx.form.password.value.value;
|
|
91
|
+
if (value && password && value !== password) {
|
|
92
|
+
return { code: 'mismatch', message: 'Passwords do not match' };
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// 4. Behavior schema
|
|
99
|
+
behavior = (path) => {
|
|
100
|
+
// Clear confirmPassword when password changes (if not empty)
|
|
101
|
+
watchField(path.password, (_, ctx) => {
|
|
102
|
+
const confirmValue = ctx.form.confirmPassword.value.value;
|
|
103
|
+
if (confirmValue) {
|
|
104
|
+
ctx.form.confirmPassword.setValue('', { emitEvent: false });
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// 5. Registration form component
|
|
110
|
+
function RegistrationFormExample() {
|
|
111
|
+
const form = useMemo(
|
|
112
|
+
() =>
|
|
113
|
+
createForm<RegistrationForm>({
|
|
114
|
+
form: formSchema,
|
|
115
|
+
validation: validationSchema,
|
|
116
|
+
behavior: behaviorSchema,
|
|
117
|
+
}),
|
|
118
|
+
[]
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
await form.validate();
|
|
124
|
+
if (form.valid.value) {
|
|
125
|
+
console.log('Form data:', form.value.value);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<form onSubmit={handleSubmit}>
|
|
131
|
+
<FormField label="Username" control={form.username} />
|
|
132
|
+
<FormField label="Email" control={form.email} />
|
|
133
|
+
<FormField label="Password" control={form.password} />
|
|
134
|
+
<FormField label="Confirm Password" control={form.confirmPassword} />
|
|
135
|
+
<button type="submit">Register</button>
|
|
136
|
+
</form>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
MIT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { effect as _ } from "@preact/signals-core";
|
|
2
|
+
import { b as v } from "../registry-helpers-Bv_BJ1s-.js";
|
|
3
|
+
import { r as V } from "../safe-effect-Dh8uw81c.js";
|
|
4
|
+
function N(n, i, s, f) {
|
|
5
|
+
const { debounce: p, condition: u } = f || {}, h = (r, E, m) => {
|
|
6
|
+
const a = r.getFieldByPath(i.__path);
|
|
7
|
+
if (!a) return null;
|
|
8
|
+
const o = n.map((e) => r.getFieldByPath(e.__path)).filter((e) => e !== void 0);
|
|
9
|
+
return o.length === 0 ? null : _(() => {
|
|
10
|
+
o.forEach((e) => e.value.value), m(() => {
|
|
11
|
+
if (u) {
|
|
12
|
+
const t = r.getValue();
|
|
13
|
+
if (!u(t)) return;
|
|
14
|
+
}
|
|
15
|
+
const e = o.map((t) => t.value.value), l = {};
|
|
16
|
+
n.forEach((t, d) => {
|
|
17
|
+
const g = t.__path.split(".").pop() || t.__path;
|
|
18
|
+
l[g] = e[d];
|
|
19
|
+
});
|
|
20
|
+
const c = s(l);
|
|
21
|
+
a.value.peek() !== c && V(() => {
|
|
22
|
+
a.setValue(c, { emitEvent: !1 });
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
v().register(h, { debounce: p });
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
N as computeFrom
|
|
31
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { r as s } from "../safe-effect-Dh8uw81c.js";
|
|
2
|
+
import { watchField as d } from "./watch-field.js";
|
|
3
|
+
function E(l, c, m) {
|
|
4
|
+
const { when: a, fields: o = "all", transform: i, debounce: p } = m || {};
|
|
5
|
+
d(
|
|
6
|
+
l,
|
|
7
|
+
(t, n) => {
|
|
8
|
+
if (a) {
|
|
9
|
+
const f = n.form.getValue();
|
|
10
|
+
if (!a(f)) return;
|
|
11
|
+
}
|
|
12
|
+
const h = i ? i(t) : t, e = n.form.getFieldByPath(c.__path);
|
|
13
|
+
e && s(() => {
|
|
14
|
+
if (o === "all" || !o)
|
|
15
|
+
e.setValue(h, { emitEvent: !1 });
|
|
16
|
+
else {
|
|
17
|
+
const f = {};
|
|
18
|
+
o.forEach((r) => {
|
|
19
|
+
t && typeof t == "object" && (f[r] = t[r]);
|
|
20
|
+
}), "patchValue" in e && e.patchValue(f);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
{ debounce: p }
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
E as copyFrom
|
|
29
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { effect as c } from "@preact/signals-core";
|
|
2
|
+
import { b } from "../registry-helpers-Bv_BJ1s-.js";
|
|
3
|
+
import { r as d } from "../safe-effect-Dh8uw81c.js";
|
|
4
|
+
function h(t, n, r) {
|
|
5
|
+
const { debounce: o, resetOnDisable: a = !1 } = r || {}, i = (s, m, l) => {
|
|
6
|
+
const e = s.getFieldByPath(t.__path);
|
|
7
|
+
return e ? c(() => {
|
|
8
|
+
const f = s.value.value;
|
|
9
|
+
l(() => {
|
|
10
|
+
const u = n(f);
|
|
11
|
+
d(() => {
|
|
12
|
+
u ? e.enable() : (e.disable(), a && e.reset());
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
}) : null;
|
|
16
|
+
};
|
|
17
|
+
b().register(i, { debounce: o });
|
|
18
|
+
}
|
|
19
|
+
function _(t, n, r) {
|
|
20
|
+
h(t, (o) => !n(o), r);
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
_ as disableWhen,
|
|
24
|
+
h as enableWhen
|
|
25
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { effect as c } from "@preact/signals-core";
|
|
2
|
+
import { b as d } from "../registry-helpers-Bv_BJ1s-.js";
|
|
3
|
+
import { r as h } from "../safe-effect-Dh8uw81c.js";
|
|
4
|
+
function R(r, n, o) {
|
|
5
|
+
const { debounce: s, resetValue: u = null, onlyIfDirty: a = !1 } = o || {}, i = (t, m, l) => {
|
|
6
|
+
const e = t.getFieldByPath(r.__path);
|
|
7
|
+
return e ? c(() => {
|
|
8
|
+
const f = t.value.value;
|
|
9
|
+
l(() => {
|
|
10
|
+
if (n(f)) {
|
|
11
|
+
if (a && !e.dirty.value)
|
|
12
|
+
return;
|
|
13
|
+
h(() => {
|
|
14
|
+
e.setValue(u), e.markAsPristine(), e.markAsUntouched();
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}) : null;
|
|
19
|
+
};
|
|
20
|
+
d().register(i, { debounce: s });
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
R as resetWhen
|
|
24
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { effect as d } from "@preact/signals-core";
|
|
2
|
+
import { b as h } from "../registry-helpers-Bv_BJ1s-.js";
|
|
3
|
+
function p(o, a, i) {
|
|
4
|
+
const { debounce: l } = i || {}, u = (t, s, c) => {
|
|
5
|
+
const r = t.getFieldByPath(o.__path);
|
|
6
|
+
if (!r) return null;
|
|
7
|
+
const n = a.map((e) => t.getFieldByPath(e.__path)).filter((e) => e !== void 0);
|
|
8
|
+
return n.length === 0 ? null : d(() => {
|
|
9
|
+
n.forEach((e) => e.value.value), c(() => {
|
|
10
|
+
r.validate();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
h().register(u, { debounce: l });
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
p as revalidateWhen
|
|
18
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { effect as o } from "@preact/signals-core";
|
|
2
|
+
import { b as v } from "../registry-helpers-Bv_BJ1s-.js";
|
|
3
|
+
import { r as i } from "../safe-effect-Dh8uw81c.js";
|
|
4
|
+
function E(u, f, c) {
|
|
5
|
+
const { debounce: d, transform: a } = c || {}, p = (n, h, l) => {
|
|
6
|
+
const r = n.getFieldByPath(u.__path), s = n.getFieldByPath(f.__path);
|
|
7
|
+
if (!r || !s) return null;
|
|
8
|
+
let e = !1;
|
|
9
|
+
const g = o(() => {
|
|
10
|
+
const t = r.value.value;
|
|
11
|
+
e || l(() => {
|
|
12
|
+
e = !0, i(() => {
|
|
13
|
+
try {
|
|
14
|
+
const y = a ? a(t) : t;
|
|
15
|
+
s.setValue(y, { emitEvent: !1 });
|
|
16
|
+
} finally {
|
|
17
|
+
e = !1;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}), m = o(() => {
|
|
22
|
+
const t = s.value.value;
|
|
23
|
+
e || l(() => {
|
|
24
|
+
e = !0, i(() => {
|
|
25
|
+
try {
|
|
26
|
+
r.setValue(t, { emitEvent: !1 });
|
|
27
|
+
} finally {
|
|
28
|
+
e = !1;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
return () => {
|
|
34
|
+
g(), m();
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
v().register(p, { debounce: d });
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
E as syncFields
|
|
41
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { watchField as p } from "./watch-field.js";
|
|
2
|
+
function u(e, t, o) {
|
|
3
|
+
const { onUserChangeOnly: n = !1, emitEvent: m = !0, debounce: c } = o || {};
|
|
4
|
+
p(
|
|
5
|
+
e,
|
|
6
|
+
(s, i) => {
|
|
7
|
+
const a = i.form.getFieldByPath(e.__path);
|
|
8
|
+
if (!a || n && !a.touched.value)
|
|
9
|
+
return;
|
|
10
|
+
const f = t(s);
|
|
11
|
+
f !== s && a.setValue(f, { emitEvent: m });
|
|
12
|
+
},
|
|
13
|
+
{ debounce: c }
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
function r(e, t) {
|
|
17
|
+
return (o, n) => {
|
|
18
|
+
u(o, e, { ...t, ...n });
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const h = {
|
|
22
|
+
/** Перевести в верхний регистр */
|
|
23
|
+
toUpperCase: r((e) => e?.toUpperCase()),
|
|
24
|
+
/** Перевести в нижний регистр */
|
|
25
|
+
toLowerCase: r((e) => e?.toLowerCase()),
|
|
26
|
+
/** Удалить пробелы с краев */
|
|
27
|
+
trim: r((e) => e?.trim()),
|
|
28
|
+
/** Удалить все пробелы */
|
|
29
|
+
removeSpaces: r((e) => e?.replace(/\s/g, "")),
|
|
30
|
+
/** Оставить только цифры */
|
|
31
|
+
digitsOnly: r((e) => e?.replace(/\D/g, "")),
|
|
32
|
+
/** Округлить число */
|
|
33
|
+
round: r(
|
|
34
|
+
(e) => typeof e == "number" ? Math.round(e) : e
|
|
35
|
+
),
|
|
36
|
+
/** Округлить до 2 знаков после запятой */
|
|
37
|
+
roundTo2: r(
|
|
38
|
+
(e) => typeof e == "number" ? Math.round(e * 100) / 100 : e
|
|
39
|
+
)
|
|
40
|
+
};
|
|
41
|
+
export {
|
|
42
|
+
r as createTransformer,
|
|
43
|
+
u as transformValue,
|
|
44
|
+
h as transformers
|
|
45
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { effect as c } from "@preact/signals-core";
|
|
2
|
+
import { b as d } from "../registry-helpers-Bv_BJ1s-.js";
|
|
3
|
+
import { r as i } from "../safe-effect-Dh8uw81c.js";
|
|
4
|
+
function g(n, r, u) {
|
|
5
|
+
const { debounce: a, immediate: f = !1 } = u || {}, s = (l, o, m) => {
|
|
6
|
+
const e = l.getFieldByPath(n.__path);
|
|
7
|
+
return e ? (f && i(() => {
|
|
8
|
+
const t = e.value.value;
|
|
9
|
+
r(t, o);
|
|
10
|
+
}), c(() => {
|
|
11
|
+
const t = e.value.value;
|
|
12
|
+
m(() => {
|
|
13
|
+
i(() => r(t, o));
|
|
14
|
+
});
|
|
15
|
+
})) : null;
|
|
16
|
+
};
|
|
17
|
+
d().register(s, { debounce: a });
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
g as watchField
|
|
21
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { a as o, b as a, i as t, t as m } from "./index-D25LsbRm.js";
|
|
2
|
+
import { a as s, B as f } from "./registry-helpers-Bv_BJ1s-.js";
|
|
3
|
+
import { copyFrom as n } from "./behaviors/copy-from.js";
|
|
4
|
+
import { disableWhen as h, enableWhen as i } from "./behaviors/enable-when.js";
|
|
5
|
+
import { computeFrom as c } from "./behaviors/compute-from.js";
|
|
6
|
+
import { watchField as F } from "./behaviors/watch-field.js";
|
|
7
|
+
import { revalidateWhen as v } from "./behaviors/revalidate-when.js";
|
|
8
|
+
import { syncFields as b } from "./behaviors/sync-fields.js";
|
|
9
|
+
import { resetWhen as g } from "./behaviors/reset-when.js";
|
|
10
|
+
import { createTransformer as C, transformValue as I, transformers as P } from "./behaviors/transform-value.js";
|
|
11
|
+
export {
|
|
12
|
+
s as BehaviorContextImpl,
|
|
13
|
+
f as BehaviorRegistry,
|
|
14
|
+
o as apply,
|
|
15
|
+
a as applyWhen,
|
|
16
|
+
c as computeFrom,
|
|
17
|
+
n as copyFrom,
|
|
18
|
+
C as createTransformer,
|
|
19
|
+
t as default,
|
|
20
|
+
h as disableWhen,
|
|
21
|
+
i as enableWhen,
|
|
22
|
+
g as resetWhen,
|
|
23
|
+
v as revalidateWhen,
|
|
24
|
+
b as syncFields,
|
|
25
|
+
m as toBehaviorFieldPath,
|
|
26
|
+
I as transformValue,
|
|
27
|
+
P as transformers,
|
|
28
|
+
F as watchField
|
|
29
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { GroupNode } from '../nodes/group-node';
|
|
2
|
+
import { FormProxy } from '../types/form-proxy';
|
|
3
|
+
import { FormContext } from '../types/form-context';
|
|
4
|
+
import { FieldPathNode } from '../types/field-path';
|
|
5
|
+
/**
|
|
6
|
+
* Реализация {@link FormContext} для behaviors. Создаётся фреймворком и передаётся
|
|
7
|
+
* в callback'и behaviors (`watchField`, `computeFrom`, …) — напрямую инстанцировать
|
|
8
|
+
* не нужно.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { watchField } from '@reformer/core/behaviors/watch-field';
|
|
13
|
+
*
|
|
14
|
+
* watchField(path.country, (value, ctx) => {
|
|
15
|
+
* // ctx — экземпляр BehaviorContextImpl
|
|
16
|
+
* ctx.setFieldValue(path.city, '');
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare class BehaviorContextImpl<TForm> implements FormContext<TForm> {
|
|
21
|
+
/**
|
|
22
|
+
* Форма с типизированным Proxy-доступом к полям
|
|
23
|
+
*/
|
|
24
|
+
readonly form: FormProxy<TForm>;
|
|
25
|
+
private _form;
|
|
26
|
+
constructor(form: GroupNode<TForm>);
|
|
27
|
+
/**
|
|
28
|
+
* Безопасно установить значение поля по строковому пути или FieldPath
|
|
29
|
+
*
|
|
30
|
+
* Автоматически использует emitEvent: false для предотвращения циклов
|
|
31
|
+
*
|
|
32
|
+
* @param path - Строковый путь к полю или FieldPath объект
|
|
33
|
+
* @param value - Новое значение
|
|
34
|
+
*/
|
|
35
|
+
setFieldValue(path: string | FieldPathNode<TForm, unknown>, value: unknown): void;
|
|
36
|
+
/**
|
|
37
|
+
* Получить поле формы по строковому пути
|
|
38
|
+
*
|
|
39
|
+
* Используется для динамического доступа к вложенным полям, например:
|
|
40
|
+
* - `ctx.getFieldByPath('address.city')` -> FieldNode
|
|
41
|
+
* - `ctx.getFieldByPath(path.city.__path)` -> FieldNode (для nested behaviors)
|
|
42
|
+
*
|
|
43
|
+
* @param path - Строковый путь к полю (например "address.city")
|
|
44
|
+
* @returns FieldNode или undefined если поле не найдено
|
|
45
|
+
*/
|
|
46
|
+
getFieldByPath(path: string): import('../..').FormNode<import('../types').FormValue> | undefined;
|
|
47
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { GroupNode } from '../nodes/group-node';
|
|
2
|
+
import { BehaviorHandlerFn, BehaviorOptions } from './types';
|
|
3
|
+
import { AbstractRegistry } from '../utils/abstract-registry';
|
|
4
|
+
import { FormFields } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Зарегистрированный behavior с опциями
|
|
7
|
+
*/
|
|
8
|
+
export interface RegisteredBehavior {
|
|
9
|
+
/** Handler функция behavior */
|
|
10
|
+
handler: BehaviorHandlerFn<FormFields>;
|
|
11
|
+
/** Debounce в миллисекундах */
|
|
12
|
+
debounce?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Реестр behaviors для формы
|
|
16
|
+
*
|
|
17
|
+
* Каждый экземпляр GroupNode создает собственный реестр (композиция).
|
|
18
|
+
* Устраняет race conditions и изолирует формы друг от друга.
|
|
19
|
+
*
|
|
20
|
+
* Наследует AbstractRegistry для унификации:
|
|
21
|
+
* - Управления global stack
|
|
22
|
+
* - Template methods begin/end registration
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* class GroupNode {
|
|
27
|
+
* private readonly behaviorRegistry = new BehaviorRegistry();
|
|
28
|
+
*
|
|
29
|
+
* applyBehaviorSchema(schemaFn) {
|
|
30
|
+
* this.behaviorRegistry.beginRegistration(); // Pushes this to stack
|
|
31
|
+
* schemaFn(createBehaviorFieldPath(this)); // Uses getCurrent()
|
|
32
|
+
* return this.behaviorRegistry.endRegistration(this); // Pops from stack
|
|
33
|
+
* }
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare class BehaviorRegistry extends AbstractRegistry<RegisteredBehavior> {
|
|
38
|
+
/**
|
|
39
|
+
* Получить текущий активный реестр из context stack
|
|
40
|
+
*
|
|
41
|
+
* @returns Текущий активный реестр или null
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* // В schema-behaviors.ts
|
|
46
|
+
* export function copyFrom(...) {
|
|
47
|
+
* const registry = BehaviorRegistry.getCurrent();
|
|
48
|
+
* if (registry) {
|
|
49
|
+
* registry.register({ ... });
|
|
50
|
+
* }
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
static getCurrent(): BehaviorRegistry | null;
|
|
55
|
+
/**
|
|
56
|
+
* Зарегистрировать behavior handler
|
|
57
|
+
* Вызывается функциями из schema-behaviors.ts
|
|
58
|
+
*
|
|
59
|
+
* @param handler - BehaviorHandlerFn функция
|
|
60
|
+
* @param options - Опции behavior (debounce)
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const handler = createCopyBehavior(target, source, { when: ... });
|
|
65
|
+
* registry.register(handler, { debounce: 300 });
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
register<T extends FormFields>(handler: BehaviorHandlerFn<T>, options?: BehaviorOptions): void;
|
|
69
|
+
/**
|
|
70
|
+
* Завершить регистрацию и применить behaviors к форме
|
|
71
|
+
* Создает effect подписки для всех зарегистрированных behaviors
|
|
72
|
+
*
|
|
73
|
+
* @param form - GroupNode формы
|
|
74
|
+
* @returns Количество зарегистрированных behaviors и функция cleanup
|
|
75
|
+
*/
|
|
76
|
+
endRegistration<T extends FormFields>(form: GroupNode<T>): {
|
|
77
|
+
count: number;
|
|
78
|
+
cleanup: () => void;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Создать effect подписку для behavior
|
|
82
|
+
* @private
|
|
83
|
+
*/
|
|
84
|
+
private createEffect;
|
|
85
|
+
}
|