feat(#4): TanStack Form adapter — formdraft/tanstack-form subpath#11
Merged
Conversation
Closes #4. Mirrors the formdraft/rhf + formdraft/formik pattern for users on TanStack Form. const form = useForm({ defaultValues: { name: '', bio: '' }, onSubmit: async ({ value }) => { await api.submit(value); discard(); // clears storage + broadcasts + resets form }, }); const { status, lastSavedAt, discard } = useFormDraftTanstack(form, { key: 'profile-form', schema: zodAdapter(Schema), sync: api.saveProfile, }); 4 rounds of code review + adversarial audit dispatched in parallel each round. Real bugs caught and fixed before merge: R1 (LOW): type intersection `any & {...}` collapsed to `any` → explicit TanstackFormApi<T> interface with the four methods we actually call. R1 (LOW): schema-drift via Object.keys(restored) → filtered against originalDefaultsRef so stored keys outside the current schema can't be forwarded to setFieldValue. R2 (MEDIUM, B1): when useForm omits defaultValues, originalDefaults was {} → validKeys empty → restore silently no-op'd. Fixed with a fallback: if defaults are empty, use Object.keys(restored) directly (already gated by useFormDraft's schema validation). R2 (LOW-MEDIUM, B5): setFieldValue's `dontUpdateMeta: true` only suppresses meta writes — validation still runs. A form with onChange validators would paint errors against restored text the user never typed on every page load. Added `dontValidate: true`. R3 (HIGH, D2): `<form.Field name="x" defaultValue="">` is idiomatic TanStack usage. With our prior `dontUpdateMeta: true`, the field stayed `isTouched: false` after restore → TanStack's FieldApi.update re-evaluates on every render and reseeds the value back to `opts.defaultValue` when `!isTouched`. Restored data was silently wiped on every render after restore. Fixed by dropping `dontUpdateMeta` entirely — restore now marks fields as touched, blocking the reseed. R4: stale docs from D2 fix in both README and JSDoc still claimed `dontUpdateMeta` was used. Updated to describe the actual behavior + reason `dontUpdateMeta` was deliberately omitted. 10 unit tests: - persist on input change - restore from storage on mount - discard clears storage AND resets visible form - delete-back-to-default still persists deletion - restore does NOT trigger redundant sync (no flicker on page load) - restore survives across re-renders with form.Field defaultValue (D2) - restore handles nested defaultValues (subtree replacement) - restore does NOT trigger field-level validators (B5) - restore even when useForm omits defaultValues (B1) - user-types-before-restore race (deferred storage) Wired in: - package.json: ./tanstack-form export + @tanstack/react-form optional peer - tsup: tanstack-form/index entry → dist/tanstack-form/{index.mjs,.js,.d.ts} - README adds TanStack Form integration section with submit-pattern example Total 115 unit tests pass. Bundle 4.09 KB brotli (TanStack adapter in its own chunk; main entry unchanged).
b508c0e to
84fc007
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #4.
Summary
formdraft/tanstack-formexportsuseFormDraftTanstack(form, options)formdraft/rhfandformdraft/formikpattern: thin adapter overuseFormDraft, returns the persistence-layer surface (status, lastSavedAt, error, save, discard, etc.) without the value/set/patch API (TanStack Form owns those)@tanstack/react-formadded as optional peer dependencyVetting
4 rounds of code review + adversarial audit dispatched in parallel each round. Real bugs caught:
any & {...}collapsed toany→ explicitTanstackFormApi<T>interfacedefaultValues: undefinedfrom useForm → silent restore no-op (fixed with fallback to restored keys)setFieldValue'sdontUpdateMeta: truedoesn't skip validation → addeddontValidate: trueso onChange validators don't paint errors on restored data<form.Field name="x" defaultValue="">(idiomatic TanStack) silently reseeded restored values back to default on every render becausedontUpdateMetakeptisTouched: false→ droppeddontUpdateMetaentirely; restore now marks fields touchedTest plan
npm test— 115 unit tests pass (10 TanStack adapter + 105 existing)npx size-limit— 4.09 KB brotli