Changelog
Unreleased
Docs
- Rewrote
README.mdfrom a 2800-line tutorial walkthrough to a ~500-line dense reference that mirrors the style of@mongez/react-atom: top-of-file pitch, a 30-second tour, a single canonical pattern for each hook/component, table-driven rule reference, and recipe-driven sections for SSR-style submit flows, multi-step forms, React Native usage, and theBaseFormextension path. Typos, dated examples, and code-block syntax errors in the old README are gone. - The exhaustive API reference moved to
llms-full.txt(already present); the README now points at it.
Tests
- Added
vitest.config.ts(happy-dom, sibling-package source aliasing for monorepo development,node_modulesfallback in CI) matching the@mongez/react-atomconfiguration. - Added
src/__tests__/setup.tsthat registers the English validation translations once, so tests assert on real localized error strings. - Added a meaningful test suite under
src/__tests__/:useFormControl.test.tsx— value collection, dot-notation nesting into objects + arrays,ignoreEmptyValues, form-level vs control-leveldefaultValueprecedence,HiddenInput, id derivation, required / email / per-instance custom validation,preservedProps,errorsoverride, checkbox collection (checked + unchecked).submitButton.test.tsx— initial enabled state, disable-on-invalid, intentional stay-disabled after a valid submit (double-submit guard), re-enable onsubmitting(false),disable()round-trip.formEvents.test.tsx—register/unregisterlifecycle,validating/validationpayloads,validatingveto viareturn false,invalidControlsevent,dirty(true)propagation.nativeForm.test.tsx— Fragment default,componenthost wrapping, programmaticsubmit()runs validation and gatesonSubmit.rules.test.tsx— every built-in rule with at least one rejection + one acceptance case, including the compositestrongRuleper-criterion errors inerrorsList["strong.<key>"]and thestrong={{ symbol: false }}opt-out.activeForm.test.tsx—getActiveForm()/getForm(id)and the stack-restoration behavior on unmount.
CI
- Added
.github/workflows/test.ymlmatching the@mongez/react-atommatrix: Node 18/20/22 on Ubuntu, Node 20 on Windows, plus a Node 20 Ubuntu job pinned to React 19 to surface concurrent-rendering or new-API regressions early.
Package
package.json:- Added
test/test:watchscripts. - Added
@mongez/reinforcementsas an explicitdependenciesentry (was already being imported byBaseForm/useFormControland shipped via transitive resolution — now declared). - Updated
peerDependencies.reactfrom>=16.8.0to>=18.0.0to match the supported test matrix. The runtime code does not currently require any React-18-only API surface, but lower versions are not tested and are considered out of scope going forward. - Updated dev dependencies for the test stack:
vitest,happy-dom,@testing-library/react,@testing-library/dom,@vitejs/plugin-react,react-dom,@types/react,@types/react-dom,typescript. - Removed marketing-only
keywordsentries (material-io,semantic,formik); kept the substantive ones and addedreact-native,headless.
- Added
Fixed
src/rules/integer.ts:8— predicate now uses||instead of&&. PreviouslyisNaN(Number(value)) && !Number.isInteger(Number(value))short-circuited for numeric-but-non-integer inputs like"3.14"(becauseisNaNreturnedfalse), letting them pass as valid integers. The OR form fails both non-numeric AND non-integer values.src/rules/max.ts:8— replaced the falsy short-circuit (!value) with an explicit empty check (value === null || value === undefined || value === ""). The old guard treated numeric0as “no value” and skipped validation, which was logically wrong even if not exploitable in the common case.src/hooks/useFormControl.ts:484—onIniteffect no longer listsprops(a fresh object every render) in its deps. AuseRefholds the latest props, so the effect reads them without rerun pressure.src/hooks/useFormControl.ts:484—rulesdep replaced with a stable string key (rules.map(r => r.name ?? '__anonymous_<i>').join('|')). Consumers passing a freshrules={[...]}literal each render no longer retriggeronInitsubscriptions on every commit.src/components/BaseForm.ts:354-367/src/hooks/useFormControl.ts:376-396—reset()now clearsformControl.isDirtyBEFORE callingchange(), andchange()honours a newdirty: falseoption so the value write does not flip the flag back totrue. TheBaseFormper-control listener now seesisDirty === falsewhen the change event fires, pops the control out ofdirtyControls, and the aggregatedirty(false)event is fired as expected.src/hooks/useFormControl.ts:486— localevents: EventSubscription[]renamed tosubscriptionsso it no longer shadows the importedeventsmodule from@mongez/events. Cosmetic — no behaviour change.
Bugs noticed (still not fixed in this pass)
src/hooks/useFormControl.ts:268—requiresValueskip condition uses[undefined, null, ""].includes(formControl.value); the rule-level guards now use the same shape but the duplication remains. Could be consolidated to a single shared helper.
React-18 tearing risk (still flagged, not fixed)
useSubmitButton— uses theuseState + useEffect(on(event, ...))pattern, the same shape as the recently-fixed bugs in@mongez/react-atom. The proper fix isuseSyncExternalStore. Deliberately not refactored in this pass to keep the diff scoped; flagged here as a known concurrent-rendering hazard.useFormControlper-control state — held in component-localuseState(lines 120, 126, 303) AND on theformControlobject that lives in auseMemo([]). The two sources are kept in sync viasetStateafter every change. In a concurrent render where a control mutatesformControlsynchronously (e.g. an action handler callingform.change(name, value)) between two reads in the same commit, sibling subscribers reading viaformControl.<x>see the new value while the component reading via React state still sees the previous one. This is a real tear vector under concurrent mode but does not yet have a reproducer test — flagged here, not fixed.
V3.0.0 (25 Aug 2024)
- Introduced new hook useRadioInput
- extracted validation translation objects to separate objects (needs to be imported manually)
- Enhanced
useFormControlperformance, reduced unnecessary re-renders - Added
isInvalidprop touseFormControlhook return output - Allowed validation rules to be all executed or fails on first error
- New
errorsListobject is returned fromuseFormControlhook to return each rule with its rule name and error message - Form component now can accept defaultValue Object to initialize value for form fields
- New Structure for validation rules to be more readable and maintainable
- Validation rules now can be synced and
asyncfunctions
V2.1.0 (05 Nov 2023)
- Added
isDirtyto form control. - Added
isTouchedto form control.
V2.0.0 (05 Mar 2023)
- Refactored code
- Replaced
useFormInputwithuseFormControl - Changed
onSubmitcallback options. - Added
useSubmitButtonhook. - Validation rules are now internally added in the package.
- Added
EnglishArabicFrenchItalianandSpanishtranslations.
V1.5.25 (13 Nov 2022)
- Feat: when
validatingtrigger callbacks returnsfalsethen the form will be marked as invalid and won’t be submitted.
V1.5.20 (06 Nov 2022)
- Added
formControl.elementto get the form control element. - Added
formControl.isCheckedto check if the form control is checked or not. - Added
formControl.blurto blur the form control. - Added
formControl.isHiddento check if the form control is hidden or not.
V 1.5.12 (17 Aug 2022)
- Added
checkIfIsValidmethod to form interface
V 1.5.11 (17 Aug 2022)
- Fixed form
validControlsandinvalidControlsvalidation events trigger.
V 1.5.3 (12 July 2022)
- Fixed form control reset value.
V 1.5.2 (12 July 2022)
- Fixed form submission.
V 1.5.1 (12 July 2022)
- Fixed exclude props.
V 1.5.0 (12 July 2022)
- Added Active Forms.
- Fixed some bugs.
V 1.4.0 (09 July 2022)
- Added
validateprop to form control. - Added
errorsprop to form control.
V 1.3.0 (03 July 2022)
- Added Form Control Events.
V 1.2.4 (18 Jun 2022)
- Fixed form input registering.
V 1.2.3 (18 Jun 2022)
- Fixed
disablemethod.
V 1.2.2 (17 Jun 2022)
- Fixed
eachmethod.
V 1.2.1 (15 Jun 2022)
validateandvalidateVisiblemethods return the validated form controls.
V 1.2.0 (15 Jun 2022)
- Fixed
validatemethod to allow calling it without any parameters. - Added validateVisible method
V 1.1.0 (16 May 2022)
- Added
changeform event. - Added Dirty Form Controls.
- Added useFormEvent Hook
V 1.0.11 (04 Mar 2022)
- Fixed Bugs
V 1.0.7 (26 Jan 2022)
- Fixed Filtering form controls in
eachmethod.