feat: JsonField and a Json column handler for forms - #107
Closed
matej21 wants to merge 2 commits into
Closed
Conversation
'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
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
This was referenced Sep 9, 2026
Member
Author
|
Consolidated into #109, merged there. |
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.
Adds first-class JSON support to forms, in two layers.
1.
createJsonHandler()inbindx-form'Json'was already a declaredColumnType, butdefaultTypeHandlershad no entry for it, so a json column fell back to the string handler:formatValuerendered an object as[object Object]andparseValuewrote a raw string into a jsonb column.<FormInput>over a json column was broken today, independently of the missing component.The new handler is registered for
ColumnType 'Json', so plain<FormInput>over a json column now works with no extra wiring:formatValuepretty-prints (JSON.stringify(value, null, 2)), but returns the user's raw text while that text still corresponds to the current value — the same state patterncreateDoubleHandleruses, so half-typed JSON is not reformatted under the cursor.parseValueparses; on failure it keeps the previous value instead of writing garbage.emptyValue(defaultnull).validatefor shape checks beyond syntax.formatOnBlurpretty-prints the input when the field loses focus.2. The parse error is a client error on the field
An unparseable value must not be silently savable, so the handler reports the failure and
FormInputadds it viafield.addError(). It renders inline through the existingFormError/data-invalidpath andBatchPersisterrefuses to persist an entity with client errors.setValueclears non-sticky client errors, so the error disappears by itself as soon as the text parses again.Three small additions in
bindx-formcarry that:FormInputHandlerContextgainscurrentValue(so a handler can keep the value it cannot parse) andsetError(applied byFormInputafter the value is written, sincesetValueclears client errors).FormInputHandlergains an optionalonBlur, used for pretty-print-on-blur and to re-report the error afteruseFormInputValidationHandlerclears the field's errors on blur.FormInputProps/useFormInputHandleraccept ahandleroverride, so a component can supply a configured handler instead of relying on schema metadata.JSONValueis defined inbindx-formand is structurally identical to theJSONValuethatbindx-generatoremits into generated entity types, so a generated json column matches without a cast.3.
JsonFieldinbindx-uiA thin wrapper in the style of
TextareaField(FormFieldScope→FormContainer→FormInput→TextareaAutosize), exported from the form barrel and the package root.fieldFieldRef<JSONValue | null>label/descriptionReactNodeFormContainerPropsrequiredbooleaninputPropsComponentProps<typeof TextareaAutosize>minRows/maxRows, … — the convention the other field components use forrows/placeholderemptyValueJSONValue | nullnullvalidate(value: JSONValue) => string | nullformatOnBlurbooleanfalseNo schema-aware editor — explicitly out of scope, as the issue proposes.
Unlike the workaround in the issue, the component keeps no local mirror of the value, so there is no server-data seed sync to get wrong: the raw text lives in the input handler's state and is only preferred over the formatted value while it still parses to the current value.
Tests
17 new tests (
packages/bindx-form/tests/jsonInput.test.tsx,packages/bindx-ui/tests/jsonField.test.tsx): value round-trips through the accessor as a value and not a string, handler resolution from theJsoncolumn type, raw text not reformatted mid-typing, invalid JSON shows the error and keeps the previous accessor value, the error survives blur, it clears when the text parses again, persist is blocked while it is present and succeeds after the fix, empty input writesemptyValue(default and custom),validatefailures, andformatOnBlur.Full suite: 2043 pass / 0 fail.
tsc --buildclean.The reporter offered a PR; this covers the same API surface plus the missing column-type handler underneath it.
Fixes #31
🤖 Generated with Claude Code
https://claude.ai/code/session_01Euwkf2wtutqvtE4YRutU5R