formstand 0.4.0 → 0.5.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/CHANGELOG.md +163 -12
- package/dist/index.cjs +41 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +41 -25
- package/dist/index.js.map +1 -1
- package/package.json +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,141 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## formstand-cli Unreleased
|
|
4
|
+
|
|
5
|
+
- Generated array hooks drop the explicit item type
|
|
6
|
+
(`useFieldArray(form, "items")`): formstand ≥ 0.5 infers it from the
|
|
7
|
+
schema through the path — and rejects the old explicit spelling on typed
|
|
8
|
+
forms. On formstand 0.4 the generated code still compiles, with untyped
|
|
9
|
+
items.
|
|
10
|
+
- Generated shadcn output defines one `ariaInvalid` helper (used by the
|
|
11
|
+
inlined adapters and the select trigger) instead of repeating the ternary
|
|
12
|
+
four times, and the generated `FieldError` computes the message once —
|
|
13
|
+
cosmetic; runtime behavior unchanged. Internally the MUI and shadcn
|
|
14
|
+
backends now share their emitted snippets (error helper, `BoundFieldProps`,
|
|
15
|
+
the leaf switch), so the generators can't drift.
|
|
16
|
+
|
|
17
|
+
## 0.5.0 — 2026-07-09
|
|
18
|
+
|
|
19
|
+
### Breaking
|
|
20
|
+
|
|
21
|
+
- `useFieldArray` infers the item type from a `Form<TSchema>` and a typed
|
|
22
|
+
path — `useFieldArray(form, "users")` (and template paths like
|
|
23
|
+
`` `albums.${index}.tracks` ``) needs no type argument, and `push`/`insert`
|
|
24
|
+
are typed against the schema's item. Consequently the old explicit
|
|
25
|
+
`useFieldArray<TItem>(form, path)` spelling is a **compile error on typed
|
|
26
|
+
forms** (drop the generic); it remains the way to bind schema-less
|
|
27
|
+
`FieldFormApi` forms, where there is nothing to infer from. A non-array
|
|
28
|
+
path types the items as `never`; a typo'd path is rejected against the
|
|
29
|
+
full `FieldPath` union, like `useField`. Path selectors return
|
|
30
|
+
`UseFieldArrayReturn<unknown>` (dynamic paths carry no type), also like
|
|
31
|
+
`useField`.
|
|
32
|
+
|
|
33
|
+
### Fixed (site only)
|
|
34
|
+
|
|
35
|
+
- The deployed playground bundled two copies of React (the formstand alias
|
|
36
|
+
reaches outside the examples package, so its imports resolved the repo
|
|
37
|
+
root's copy) — every tab crashed at startup with a null hooks
|
|
38
|
+
dispatcher. The examples build now dedupes react/zustand/zod and CI
|
|
39
|
+
asserts the bundle holds exactly one React.
|
|
40
|
+
|
|
41
|
+
### Docs & examples (no package changes)
|
|
42
|
+
|
|
43
|
+
- The playground demos bind shadcn's `Input`/`Textarea` with the library's
|
|
44
|
+
own exported `textInputProps`/`numberInputProps` — the shadcn adapter now
|
|
45
|
+
covers only the Radix dialect, and the "field has an error" predicate
|
|
46
|
+
lives once in `examples/src/fieldErrors.ts` (shared by both adapters).
|
|
47
|
+
- The copy-in shadcn kit is trimmed to what the demos render (Badge/Button
|
|
48
|
+
variants, dead peer-disabled label classes) and every component exports a
|
|
49
|
+
`Readonly` props type.
|
|
50
|
+
|
|
51
|
+
## formstand-cli 0.2.1 — 2026-07-09
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- Leaf-free schemas (no scalar fields anywhere, e.g. an object of empty
|
|
56
|
+
objects) no longer generate non-compiling output in the `mui` and
|
|
57
|
+
`shadcn` backends — the emitted `BoundFieldProps` type referenced
|
|
58
|
+
`FieldFormApi` without importing it. All three backends now have a
|
|
59
|
+
leaf-free typecheck test.
|
|
60
|
+
- The shadcn backend's generated output is additionally typechecked in CI
|
|
61
|
+
against the repo's real Radix-based components (not just the structural
|
|
62
|
+
stub), so a shadcn/Radix prop-contract change fails our suite instead of
|
|
63
|
+
the consumer's build.
|
|
64
|
+
|
|
65
|
+
### Docs & examples (no library package changes)
|
|
66
|
+
|
|
67
|
+
- Playground: the page chrome stylesheet is unlayered again — cascade
|
|
68
|
+
layers can't be transpiled, so pre-15.4 WebKit (the es2019 target's
|
|
69
|
+
audience) was losing every tab's styling; its selectors are class-scoped,
|
|
70
|
+
so the shadcn utilities are unaffected. The layer-order statement now
|
|
71
|
+
pins Tailwind's canonical `components` slot below `utilities`.
|
|
72
|
+
- shadcn kit: sliders take an `aria-label` routed to the Radix Thumb (the
|
|
73
|
+
Root is a `<span>`, so `htmlFor`/`id` never named it); radio-group items
|
|
74
|
+
show error styling via `group-aria-invalid` (Radix doesn't propagate the
|
|
75
|
+
Root's `aria-invalid` to items); the Team demo's rows are memoized with
|
|
76
|
+
stable handlers so keystrokes in one row stop re-rendering the rest.
|
|
77
|
+
- Publish workflow: `--provenance` is explicit again (fail-closed — the
|
|
78
|
+
automatic path silently skips attestation when conditions aren't met) and
|
|
79
|
+
the Node pin is `>=24.8`, the first line whose bundled npm meets trusted
|
|
80
|
+
publishing's 11.5.1 floor. CI asserts the root and examples lockfiles
|
|
81
|
+
agree on the deduped UI packages, so the smoke test can't silently
|
|
82
|
+
certify a different build than the deployed playground.
|
|
83
|
+
|
|
84
|
+
## formstand-cli 0.2.0 — 2026-07-08
|
|
85
|
+
|
|
86
|
+
### Added
|
|
87
|
+
|
|
88
|
+
- `--ui shadcn`: generates forms against [shadcn/ui](https://ui.shadcn.com/)
|
|
89
|
+
conventions — components imported from the app's `@/components/ui/*` alias
|
|
90
|
+
(what `npx shadcn add` scaffolds), an inlined adapter speaking the Radix
|
|
91
|
+
dialect (`onCheckedChange`/`onValueChange`, dropdown-close as the blur
|
|
92
|
+
trigger), and `aria-invalid` error styling with a message line. Generated
|
|
93
|
+
output is typechecked in CI against the library source and a structural
|
|
94
|
+
stub of the shadcn components, like the other backends.
|
|
95
|
+
- `emitShadcnForm` joins the programmatic API.
|
|
96
|
+
|
|
97
|
+
### Docs & examples (no library package changes)
|
|
98
|
+
|
|
99
|
+
- Four shadcn/ui playground demos (Signup, Checkout, Settings, Team) plus
|
|
100
|
+
the formstand→shadcn adapter pattern they showcase —
|
|
101
|
+
`examples/src/shadcn/shadcnAdapter.ts` bridges `useField` to both native
|
|
102
|
+
inputs and the Radix-based widgets (Checkbox, Switch, Select, Slider,
|
|
103
|
+
RadioGroup).
|
|
104
|
+
- The playground carries its own copy-in shadcn component kit under a
|
|
105
|
+
scoped Tailwind 4 setup (no preflight; the plain-CSS and MUI demos are
|
|
106
|
+
untouched).
|
|
107
|
+
|
|
108
|
+
## 0.4.1 — 2026-07-08
|
|
109
|
+
|
|
110
|
+
### Fixed
|
|
111
|
+
|
|
112
|
+
- `submit`'s stale-write guard now uses pass ownership (cleared by
|
|
113
|
+
`reset`/`adoptValues`) in addition to the values-reference check — a bare
|
|
114
|
+
`reset()` on a pristine form during an in-flight submit no longer gets
|
|
115
|
+
stale errors and touched marks committed (reference equality couldn't see
|
|
116
|
+
it: reset restores the same `initialValues` reference).
|
|
117
|
+
- `restore()` no longer resurrects in-flight validation flags captured in a
|
|
118
|
+
snapshot (`isValidating`/`isValidatingForm` are transient, owned by live
|
|
119
|
+
passes — a restored copy could stick forever).
|
|
120
|
+
- `focusFirstError`/`focusField` verify focus against the element's own root
|
|
121
|
+
node, fixing a regression that walked past every candidate inside a shadow
|
|
122
|
+
root and reported failure after moving focus to the wrong control.
|
|
123
|
+
- `focusField("")` focuses the form's first focusable control (whole-form
|
|
124
|
+
scope, like its imperative siblings), with the same multi-form
|
|
125
|
+
refuse-to-guess rule as `focusFirstError`.
|
|
126
|
+
- `field.setError("string")` is normalized to an array before reaching
|
|
127
|
+
`FieldFormApi.setError`, shielding pre-0.4 custom implementations typed
|
|
128
|
+
for `readonly string[]`.
|
|
129
|
+
|
|
130
|
+
### Internal
|
|
131
|
+
|
|
132
|
+
- Validation pass ownership uses unique `Symbol()` tokens — collisions after
|
|
133
|
+
`reset`/`adoptValues` are impossible by construction rather than guarded
|
|
134
|
+
by a never-reset counter invariant.
|
|
135
|
+
- Publish workflow fails fast when the pushed tag doesn't match
|
|
136
|
+
`package.json`'s version; the CLI release checklist pushes the release
|
|
137
|
+
commit, not just the tag.
|
|
138
|
+
|
|
3
139
|
## 0.4.0 — 2026-07-08
|
|
4
140
|
|
|
5
141
|
### Breaking
|
|
@@ -22,10 +158,13 @@
|
|
|
22
158
|
- `adoptValues` now clears the in-flight validation flags
|
|
23
159
|
(`isValidating` / `isValidatingForm`) along with the errors it already
|
|
24
160
|
cleared — the rebase disowns in-flight passes.
|
|
25
|
-
- `submit` skips its error/touched state writes when
|
|
26
|
-
validation was in flight
|
|
27
|
-
|
|
28
|
-
|
|
161
|
+
- `submit` skips its error/touched state writes when the form was rebased
|
|
162
|
+
while validation was in flight: when `values` changed, when `reset` /
|
|
163
|
+
`adoptValues` ran (including a bare `reset()` on a pristine form, where the
|
|
164
|
+
values reference doesn't change), or when a concurrent
|
|
165
|
+
`submit({ force: true })` re-claimed ownership (the LAST submit's writes
|
|
166
|
+
land). `onValid`/`onInvalid` still run and the result still reports the
|
|
167
|
+
outcome.
|
|
29
168
|
|
|
30
169
|
### Added
|
|
31
170
|
|
|
@@ -35,11 +174,16 @@
|
|
|
35
174
|
behind `useField().emptyValue`, alongside its adapter siblings
|
|
36
175
|
`numberToInputText` / `parseNumberText`.
|
|
37
176
|
- `field.setError` (from `useField`) accepts a single string, matching
|
|
38
|
-
`form.setError`.
|
|
39
|
-
|
|
40
|
-
`
|
|
41
|
-
|
|
42
|
-
|
|
177
|
+
`form.setError`. The hook normalizes the shorthand to a one-element array
|
|
178
|
+
before forwarding, so custom `FieldFormApi` implementations typed for
|
|
179
|
+
`readonly string[]` never receive a bare string.
|
|
180
|
+
- `focusField("")` focuses the first focusable control in scope (the
|
|
181
|
+
whole-form `""` semantics of the imperative surface); under the default
|
|
182
|
+
`document` scope it refuses to guess between multiple `<form>`s, like
|
|
183
|
+
`focusFirstError`'s root-`""` fallback.
|
|
184
|
+
- `validateField` / `validateFieldAsync` targeting a path the schema
|
|
185
|
+
provably cannot contain now warn (once per path per form) — protects the
|
|
186
|
+
docs-sanctioned dynamic-path casts from silent always-valid results.
|
|
43
187
|
- Docs: a migrating-from-react-hook-form guide with the full API mapping
|
|
44
188
|
table.
|
|
45
189
|
|
|
@@ -48,9 +192,16 @@
|
|
|
48
192
|
- Array ops no longer strand in-flight `isValidating` flags: flags under the
|
|
49
193
|
path are dropped rather than re-keyed (the completing pass clears the
|
|
50
194
|
original key, so a re-keyed flag could never be cleared).
|
|
51
|
-
-
|
|
52
|
-
a superseded pre-reset validation pass can
|
|
53
|
-
post-reset one and clobber its state.
|
|
195
|
+
- In-flight validation passes are owned via unique symbol tokens (unique by
|
|
196
|
+
construction), so a superseded pre-reset validation pass can never collide
|
|
197
|
+
with a post-reset one and clobber its state.
|
|
198
|
+
- `restore(snapshot)` clears the transient in-flight flags (`isValidating` /
|
|
199
|
+
`isValidatingForm`) instead of restoring them — in-flight state is owned
|
|
200
|
+
by live passes, never by snapshots, so a restored flag would stick forever.
|
|
201
|
+
- `focusFirstError` / `focusField` verify focus against the element's own
|
|
202
|
+
root (`getRootNode().activeElement`), so controls inside a shadow root are
|
|
203
|
+
no longer reported as unfocused (`document.activeElement` retargets to the
|
|
204
|
+
shadow host).
|
|
54
205
|
- `validateFieldAsync("")` delegates to the whole-form pass, so its pending
|
|
55
206
|
state lives in `isValidatingForm` instead of `isValidating[""]`.
|
|
56
207
|
- `focusFirstError` / `focusField` report success only when a control
|
package/dist/index.cjs
CHANGED
|
@@ -274,6 +274,7 @@ var dirtyPathsOf = (values, initial, prefix) => {
|
|
|
274
274
|
return [prefix];
|
|
275
275
|
};
|
|
276
276
|
var FORM_SEQ_KEY = "__form__";
|
|
277
|
+
var SUBMIT_SEQ_KEY = "__submit__";
|
|
277
278
|
var stringArraysEqual = (a, b) => a === b || a.length === b.length && a.every((v, i) => v === b[i]);
|
|
278
279
|
var reuseErrorRefs = (next, prev) => {
|
|
279
280
|
if (next === prev) return prev;
|
|
@@ -466,19 +467,18 @@ var createForm = (schema, options) => {
|
|
|
466
467
|
};
|
|
467
468
|
};
|
|
468
469
|
const sequences = /* @__PURE__ */ new Map();
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
return seqRef.current;
|
|
470
|
+
const claimPass = (key) => {
|
|
471
|
+
const pass = Symbol(key);
|
|
472
|
+
sequences.set(key, pass);
|
|
473
|
+
return pass;
|
|
474
474
|
};
|
|
475
475
|
const validateAsyncOnForm = async () => {
|
|
476
|
-
const
|
|
476
|
+
const pass = claimPass(FORM_SEQ_KEY);
|
|
477
477
|
const valuesAtStart = store.getState().values;
|
|
478
478
|
store.setState((state) => ({ ...state, isValidatingForm: true }));
|
|
479
479
|
const result = await validateAsync(schema, valuesAtStart);
|
|
480
480
|
const live = store.getState();
|
|
481
|
-
const stillOwns = sequences.get(FORM_SEQ_KEY) ===
|
|
481
|
+
const stillOwns = sequences.get(FORM_SEQ_KEY) === pass;
|
|
482
482
|
if (!stillOwns || live.values !== valuesAtStart) {
|
|
483
483
|
if (stillOwns) {
|
|
484
484
|
store.setState((state) => ({ ...state, isValidatingForm: false }));
|
|
@@ -501,7 +501,7 @@ var createForm = (schema, options) => {
|
|
|
501
501
|
const result2 = await validateAsyncOnForm();
|
|
502
502
|
return result2.kind === "valid";
|
|
503
503
|
}
|
|
504
|
-
const
|
|
504
|
+
const passes = new Map(paths.map((p) => [p, claimPass(p)]));
|
|
505
505
|
const valuesAtStart = store.getState().values;
|
|
506
506
|
store.setState((state) => ({
|
|
507
507
|
...state,
|
|
@@ -516,7 +516,9 @@ var createForm = (schema, options) => {
|
|
|
516
516
|
(k) => !inScopeOfAny(k, paths)
|
|
517
517
|
);
|
|
518
518
|
const live = store.getState();
|
|
519
|
-
const stillCurrent = paths.filter(
|
|
519
|
+
const stillCurrent = paths.filter(
|
|
520
|
+
(p) => sequences.get(p) === passes.get(p)
|
|
521
|
+
);
|
|
520
522
|
if (live.values !== valuesAtStart) {
|
|
521
523
|
if (stillCurrent.length > 0) {
|
|
522
524
|
store.setState((state) => ({
|
|
@@ -557,7 +559,7 @@ var createForm = (schema, options) => {
|
|
|
557
559
|
result.kind === "invalid" ? result.errors : emptyErrors
|
|
558
560
|
);
|
|
559
561
|
}
|
|
560
|
-
const
|
|
562
|
+
const pass = claimPass(path);
|
|
561
563
|
const valuesAtStart = store.getState().values;
|
|
562
564
|
store.setState((state) => ({
|
|
563
565
|
...state,
|
|
@@ -565,7 +567,7 @@ var createForm = (schema, options) => {
|
|
|
565
567
|
}));
|
|
566
568
|
const scoped = await scopedFieldErrorsAsync(path, valuesAtStart);
|
|
567
569
|
const live = store.getState();
|
|
568
|
-
const stillOwns = sequences.get(path) ===
|
|
570
|
+
const stillOwns = sequences.get(path) === pass;
|
|
569
571
|
if (!stillOwns || live.values !== valuesAtStart) {
|
|
570
572
|
if (stillOwns) {
|
|
571
573
|
store.setState((state) => ({
|
|
@@ -644,11 +646,12 @@ var createForm = (schema, options) => {
|
|
|
644
646
|
submitCount: state.submitCount + 1
|
|
645
647
|
}));
|
|
646
648
|
try {
|
|
649
|
+
const pass = claimPass(SUBMIT_SEQ_KEY);
|
|
647
650
|
const valuesAtStart = store.getState().values;
|
|
648
651
|
const result = await validateAsync(schema, valuesAtStart);
|
|
649
|
-
const
|
|
652
|
+
const stale = sequences.get(SUBMIT_SEQ_KEY) !== pass || store.getState().values !== valuesAtStart;
|
|
650
653
|
if (result.kind === "invalid") {
|
|
651
|
-
if (!
|
|
654
|
+
if (!stale) {
|
|
652
655
|
store.setState((state) => {
|
|
653
656
|
const committed = commitFullPass(state, result.errors);
|
|
654
657
|
return {
|
|
@@ -666,11 +669,11 @@ var createForm = (schema, options) => {
|
|
|
666
669
|
};
|
|
667
670
|
});
|
|
668
671
|
}
|
|
669
|
-
const merged =
|
|
672
|
+
const merged = stale ? result.errors : store.getState().errors;
|
|
670
673
|
onInvalid?.(merged);
|
|
671
674
|
return { kind: "invalid", errors: merged };
|
|
672
675
|
}
|
|
673
|
-
if (!
|
|
676
|
+
if (!stale) {
|
|
674
677
|
store.setState((state) => ({
|
|
675
678
|
...state,
|
|
676
679
|
...commitFullPass(state, emptyErrors)
|
|
@@ -923,7 +926,13 @@ var createForm = (schema, options) => {
|
|
|
923
926
|
errors: reuseErrorRefs(
|
|
924
927
|
mergeErrorChannels(schemaErrors, serverErrors),
|
|
925
928
|
snap.errors ?? emptyErrors
|
|
926
|
-
)
|
|
929
|
+
),
|
|
930
|
+
// In-flight state is owned by live passes, never by snapshots: a
|
|
931
|
+
// snapshotted flag has no pass left to clear it (the pass that set
|
|
932
|
+
// it cleared its ORIGINAL entry when it settled), so restoring one
|
|
933
|
+
// would stick it forever.
|
|
934
|
+
isValidating: emptyBools,
|
|
935
|
+
isValidatingForm: false
|
|
927
936
|
};
|
|
928
937
|
})
|
|
929
938
|
});
|
|
@@ -1079,7 +1088,10 @@ function useField(form, pathArg, options) {
|
|
|
1079
1088
|
[form, path]
|
|
1080
1089
|
);
|
|
1081
1090
|
const setError = react.useCallback(
|
|
1082
|
-
|
|
1091
|
+
// Normalize the string shorthand HERE, before forwarding: custom
|
|
1092
|
+
// FieldFormApi implementations written against the pre-0.4 surface are
|
|
1093
|
+
// typed for readonly string[] and must never receive a bare string.
|
|
1094
|
+
(errors) => form.setError(path, typeof errors === "string" ? [errors] : errors),
|
|
1083
1095
|
[form, path]
|
|
1084
1096
|
);
|
|
1085
1097
|
const clearError = react.useCallback(
|
|
@@ -1348,9 +1360,14 @@ var focusableControls = (scope) => [
|
|
|
1348
1360
|
].filter(
|
|
1349
1361
|
(el) => !el.matches(':disabled, [type="hidden"]') && el.closest("dialog:not([open])") === null
|
|
1350
1362
|
);
|
|
1363
|
+
var holdsFocus = (el) => {
|
|
1364
|
+
const rootNode = el.getRootNode();
|
|
1365
|
+
const active = rootNode instanceof Document || rootNode instanceof ShadowRoot ? rootNode.activeElement : document.activeElement;
|
|
1366
|
+
return active === el;
|
|
1367
|
+
};
|
|
1351
1368
|
var focusFirstOf = (candidates) => candidates.some((el) => {
|
|
1352
1369
|
el.focus();
|
|
1353
|
-
return
|
|
1370
|
+
return holdsFocus(el);
|
|
1354
1371
|
});
|
|
1355
1372
|
var nameMatchesAny = (el, paths) => {
|
|
1356
1373
|
const name = el.getAttribute("name");
|
|
@@ -1370,11 +1387,10 @@ var focusFirstError = (errors, root) => {
|
|
|
1370
1387
|
const candidates = fieldMatches.length > 0 ? fieldMatches : rootFallbackApplies ? controls : [];
|
|
1371
1388
|
return focusFirstOf(candidates);
|
|
1372
1389
|
};
|
|
1373
|
-
var focusField = (path, root) =>
|
|
1374
|
-
focusableControls(root ?? document)
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
);
|
|
1390
|
+
var focusField = (path, root) => {
|
|
1391
|
+
const controls = focusableControls(root ?? document);
|
|
1392
|
+
return path === "" ? (root !== void 0 || document.querySelectorAll("form").length <= 1) && focusFirstOf(controls) : focusFirstOf(controls.filter((el) => nameMatchesAny(el, [path])));
|
|
1393
|
+
};
|
|
1378
1394
|
var EMPTY_ID_STATE = { items: [], ids: [], counter: 0 };
|
|
1379
1395
|
var EMPTY_ITEMS = [];
|
|
1380
1396
|
var reconcileIds = (prev, nextItems) => {
|
|
@@ -1413,7 +1429,7 @@ var reconcileIds = (prev, nextItems) => {
|
|
|
1413
1429
|
counter: prev.counter + Math.max(0, unmatched - leftover.length)
|
|
1414
1430
|
};
|
|
1415
1431
|
};
|
|
1416
|
-
|
|
1432
|
+
function useFieldArray(form, pathArg) {
|
|
1417
1433
|
const path = react$1.useStore(
|
|
1418
1434
|
form.store,
|
|
1419
1435
|
(state) => typeof pathArg === "function" ? pathArg(state) : pathArg
|
|
@@ -1478,7 +1494,7 @@ var useFieldArray = (form, pathArg) => {
|
|
|
1478
1494
|
}),
|
|
1479
1495
|
[fields, items, error, push, remove, insert, move, swap]
|
|
1480
1496
|
);
|
|
1481
|
-
}
|
|
1497
|
+
}
|
|
1482
1498
|
|
|
1483
1499
|
exports.CheckboxField = CheckboxField;
|
|
1484
1500
|
exports.NumberField = NumberField;
|