Consolidate #108, #107, #106, #105, #104 - #109
Merged
Merged
Conversation
Blurring an input clears all errors on the field, so a server validation error and a client error raised elsewhere both vanish while the value is still invalid. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R (cherry picked from commit 27e48ac)
The handler tags the HTML5 validation message it adds with a code and clears exactly that error, instead of resetting the whole field. Field-error clearing now takes a FieldErrorFilter (source and/or code) in place of the source-only argument the store already accepted but nothing passed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R (cherry picked from commit 2408c98)
'Json' was already a declared ColumnType with no handler, so a json column fell back to the string handler: the formatter rendered [object Object] and the parser wrote a raw string into a jsonb column. createJsonHandler() parses the input into a JSON value, keeps the user's raw text while it still matches the current value, keeps the previous value when the text does not parse, and reports the failure through the new ctx.setError, which FormInput turns into a client error on the field. That surfaces inline and blocks persist until the text parses again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R (cherry picked from commit 24f33c7)
Entities with c.jsonColumn() fields had no first-class form component, so every consumer rebuilt the JSON round-trip, the seed sync and the inline parse-error UX by hand. JsonField mirrors TextareaField and drives the Json handler, with emptyValue, an optional validate for shape checks, and formatOnBlur. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R (cherry picked from commit cdf99a2)
Uploader and MultiUploader hard-coded every UploaderEvents handler to a noop, so there was no supported way to intervene between "files dropped" and "the uploader writes into the target entity". Both now accept the event callbacks as optional props and compose them with the internal accept-type resolution, disconnect and extractor fill. Uploader also gains prepareTarget: it runs once per batch, before the target is disconnected or filled, and the target it returns is what the upload lands on. This unblocks copy-on-write flows where a shared, already-persisted row must be forked first instead of mutated in place. Fixes #63 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R (cherry picked from commit 0ed377b)
…idation prepareTarget ran before the accept check, so dropping an unacceptable file into an uploader forked the target and then rejected every file: the relation ended up pointing at a fresh empty entity instead of the shared one it had. Losing a reference by dropping the wrong file is a worse outcome than the redundant work it was meant to avoid. It now runs after the prepare/filter phase, receives the accepted files, and is skipped when none passed. A throw still reports the batch through onError and abandons it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R (cherry picked from commit 60442a3)
(cherry picked from commit a1b4444)
DataViewExportTrigger built its unpaged query from filtering.resolvedWhere only, so a grid's static `filter` prop never reached the export and the file carried rows outside the grid's visible scope. On HasManyDataGrid it went further: a root list query over the whole target entity table, with no parent constraint at all. The context now carries `fetchAllData`, and each view implements it as the query it already loads with, minus paging — DataGrid and SelectDataView as their list query with the combined filter, HasManyDataGrid as the same GET on the parent record. Exposing a filter instead would leave the next view free to forget to combine it; owning the query shape cannot be forgotten. Fixes #67 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R (cherry picked from commit 36a8f87)
The reporter's repro covers the static filter on a root DataGrid. This adds the has-many half: the export must read the relation through the parent record, so it can never reach another parent's rows. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R (cherry picked from commit 7d1eb6e)
DataGridToolbarUI hard-coded <DataGridAutoExport />, and the context feeding its mobile filter chips was private, so swapping the export meant rebuilding the toolbar and losing the mobile filters toggle. Adds an `exportControl` slot (null hides it) and exports DataGridShowFiltersContext. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R (cherry picked from commit 6d77c89)
…ocus A permanent dashed underline in every relation and enum cell reads as "link" or "has a tooltip", while it actually means "click for filter actions" — permanent noise for a power-user feature. The decoration stays underline-based, so the wrapped-text fix from 2bbd12f is preserved; only its color is now transparent at rest. The label becomes focusable and the tooltip opens on focus-within, so the filter actions are reachable without a mouse. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R (cherry picked from commit bad1f2e)
The header icon used to appear only once a filter was set, so nothing told an operator which columns can be filtered. It now always renders: muted when idle, blue when a filter is active. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R (cherry picked from commit d8f49c5)
Consolidation fix for the interaction between #107 and #108. #107 built createJsonHandler against a blur that wiped every error on the field, so its onBlur re-reported the parse error to survive that wipe. #108 narrowed the blur to clear only its own html5-validity error, so the parse error now survives on its own and the re-report adds a second copy of it — one more on every blur, unbounded until the next keystroke clears non-sticky errors. Neither PR's tests caught it: the rendered error list does not re-render on the blur, so the duplicates were only visible to a fresh read of the field. The added test reads the field errors from the store for that reason. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R
This was referenced Sep 10, 2026
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.
Combines five open PRs into one branch. Each PR's own commits are cherry-picked with
-x, in the order listed.Conflicts
None. All twelve commits applied cleanly;
packages/bindx-form/src/index.tsis the only file two PRs touch, and both edits are additive exports that merged automatically.Deviation from the originals
One extra commit,
fix(bindx-form): drop the Json handler's blur re-report, resolves a semantic conflict between #107 and #108 that git could not see — the two PRs touch different files.#107 wrote
createJsonHandler.onBluragainst the blur behaviour onmain, whereuseFormInputValidationHandlercleared every error on the field. To survive that wipe, the handler re-reported its parse error on each blur. #108 narrows the blur to clear only its ownhtml5-validityerror, so the parse error now survives by itself — and the re-report appends a second copy of it. One more copy on every blur, unbounded until the next keystroke clears non-sticky errors.The commit removes the re-report and keeps the rest of
onBlur(theformatOnBlurreflow, still skipped while the input is broken).Neither PR's tests caught this: the rendered error list does not re-render on the blur, so the duplicates were invisible to a DOM assertion. Measured on the consolidated branch before the fix — 1 error after the change, then 2, 3, 4 after successive blurs; on #107 alone it stays at 1. The added regression test reads the field errors from the store for that reason, and fails with 3 against the unfixed handler.
Verification
packages/bindx-form/src/index.ts— accounted for, nothing lost.clearErrors(source)signature toclearErrors(filter); no call site in any of the other four PRs uses the old string form.packages/bindx-ui/src/datagrid/, but on disjoint concerns (filter-icon rendering and tooltip focus vs. the toolbar export slot). feat(bindx-uploader): let consumers retarget an upload before it writes #106 is self-contained.bun run typecheck,bun run lint,bun run test— 2059 pass, 0 fail.🤖 Generated with Claude Code
https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R