feat(sdui): render free-text form inputs + bridge page variables into submit actions#1995
Merged
Conversation
… submit actions
SDUI pages could display and navigate but not collect data-entry input. This
closes both gaps so a pure-SDUI page can render a working form.
Gap 1 — free-text input element. Add `element:text_input`, a labeled input that
writes the typed value into a page variable via `usePageVariableBinding`
(`PageVariableSchema.source`), mirroring `element:record_picker`. One element
covers the free-text family via `inputType` (text/email/number/tel/url/password);
number inputs coerce to a numeric value. Registered in the ComponentRegistry.
Gap 2 — input→submit bridge. `PageVariableActionBridge` publishes the live
page-variable snapshot into the shared ActionRunner context as `pageVariables`
(mirroring how ObjectGrid publishes `selectedRecords`); it is mounted inside
`PageVariablesProvider` in the page layout renderer. `apiHandler` gains a
`context` param and resolves `{{page.<var>}}` tokens in the request params/body
against that snapshot (type-preserving for whole-value tokens) — so a submit
`element:button` (or any api/onClick action) can post the values the inputs
wrote. New `resolvePageVarTokens` util; `pageVariables` added to ActionContext.
Tests: text_input renderer (write/inputType/number-coercion/default-seed/no-binding);
apiHandler token resolution + an end-to-end input→variable→submit loop;
resolvePageVarTokens unit coverage.
Pairs with the framework spec PR (adds the `element:text_input` schema + the
`showcase_contact_form` demo).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
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.
Why
SDUI pages could display and navigate but not collect data-entry input: the only interactive input was
element:record_picker(picks existing records),element:textis display-only, and although the action runtime could POST, there was no path for page-variable values to reach a submit body. So you couldn't build a working form as a pure SDUI page. This closes both gaps.Pairs with the spec half: objectstack-ai/objectstack#2321 (adds the
element:text_inputschema + theshowcase_contact_formdemo).What
Gap 1 — free-text input element.
element:text_input(renderers/basic/text-input.tsx, mirroringrecord-picker.tsx): a labeled input reusing the existingInput/Labelprimitives that writes the typed value into a page variable viausePageVariableBinding(PageVariableSchema.source). One element covers the free-text family viainputType(text/email/number/tel/url/password);numbercoerces to a numeric value; uncontrolled + safe outside a Page. Registered in theComponentRegistry.Gap 2 — input → submit bridge.
PageVariableActionBridge(react/hooks) publishes the live page-variable snapshot into the sharedActionRunnercontext aspageVariables— mirroring howObjectGridpublishesselectedRecords— mounted insidePageVariablesProviderin the page layout renderer.apiHandlergains acontextparam and resolves{{page.<var>}}tokens in the request params/bodyExtraagainst that snapshot before the fetch (resolvePageVarTokens). Whole-value tokens preserve type (a number stays a number); embedded tokens interpolate. So a submitelement:button(or anyapi/onClickaction) posts the values the inputs wrote.pageVariablesadded toActionContext(core + types).This resolves in the shared runtime, so
element:button,action:button, andonClick-expression actions all benefit; double-brace{{page.x}}never collides with the existing single-brace{field}row-record URL interpolation.Verification
text_inputrenderer (write / inputType / number-coercion / default-seed / no-binding);apiHandlertoken resolution + an end-to-end input→variable→submit loop asserting the exact POST body;resolvePageVarTokensunit coverage. No regression inpage-variables/basic-renderers.tscacrosstypes→core→react→components→app-shell(27 tasks).page.inquiryEmail-gated hint appears live); Submit POSTs{"name":"Grace Hopper","email":"grace@example.com",...}(tokens resolved, not literal) → HTTP 201,showcase_inquirycreated.🤖 Generated with Claude Code