feat(core)!: array-element field identity via @solidjs/signals store - #10
Open
LouisHaftmann wants to merge 1 commit into
Open
feat(core)!: array-element field identity via @solidjs/signals store#10LouisHaftmann wants to merge 1 commit into
LouisHaftmann wants to merge 1 commit into
Conversation
Replaces the @vue/reactivity engine with the @solidjs/signals store. The store keeps one stable reactive node per raw object, so the field cache is keyed by engine-maintained object identity and the hand-written on-change array-mutation mirror disappears entirely. - FormFields over object array elements travel with their datum across splice/sort/reverse/unshift/reorder: same stable key, preserved dirty state and errors. Primitive-array elements stay positional. - form.data is a writable facade routing writes into the store setter; new form.setData(recipe) applies batch edits atomically. - Writes are batched and flushed on a microtask; derived state is current after the next flush. Hidden escape hatch: form['~'].flush(). - reset() and non-dirty sourceValues updates apply via reconcile (positional by default, optional reconcileKey resolver). - React adapter re-renders via subscription, Vue adapter bridges engine notifications into Vue reactivity (v-model preserved). BREAKING CHANGE: field.key format changed to a stable per-node id, array.delete(key) resolves by identity instead of parsing an index, and the read/write contract is asynchronous (flush before reading derived state in tests and imperative code). The @vue/reactivity helpers exported from form-core/reactive are removed. Closes #4 Created with AI. Verified by a human. Co-authored-by: ox-alpha <noreply@falcondev.it>
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
Editing array fields used to desync the two internal data structures (reactive form data and the field cache) on every mutation. The old design stored array items positionally and mirrored each array method (
splice,sort,reverse, …) by hand, so aFormFieldstayed bound to its index: reordering a list left dirty state, errors, and DOM rows with the slot instead of the value.This swaps the reactive engine to the
@solidjs/signalsstore (next channel). The store keeps one stable node per raw object, so field state is keyed by engine-maintained object identity and the whole mutation-mirror is gone:FormField— key, dirty state, errors, and bound DOM — attached to the element, not the index.array.delete(key)removes by identity.form.datastays directly readable/writable via a facade that routes writes into the store setter; newform.setData(recipe)applies batch edits atomically with one validation.form['~'].flush().reset()and non-dirtysourceValuesupdates apply via reconcile, positionally by default; an optionalreconcileKeyresolver preserves identity across external refreshes for id-bearing rows.useSyncExternalStore-style subscription), Vue bridges them into Vue reactivity withv-modelintact.Verified end-to-end in the playground (extended with a reorderable editable list): keys travel with rows across reorder, delete-by-key removes the right element after reorder, reset restores positionally without remounting surviving rows.
Reviews
Notable fixes from review: facades/views are now unwrapped before being stored back into the engine (slot-swap reorders used to create fresh nodes),
field.reset()on reference-node fields merges into the live node so identity survives, and the React adapter's stalesubmit/sourceValuesref sync was restored.Left unfixed, deliberately:
toVueField's explicit per-property getters (type safety over a getter loop), theclone()wrapper (preserves const-generic inference), sync mirror counters and dual listener registries (load-bearing), and JSON.stringify-based deep tracking missing opaque-leaf swaps that stringify identically (edge case, noted for later).BREAKING CHANGE:
field.keyformat changed to a stable per-node id,array.delete(key)resolves by identity instead of parsing an index, and the read/write contract is asynchronous. The@vue/reactivityhelpers exported fromform-core/reactiveare removed.Created with AI. Verified by a human.