feat(forms): field-level conditional rules — visibleWhen/readonlyWhen/requiredWhen (B2 client)#1578
Merged
Merged
Conversation
…equiredWhen (B2-PR3) Evaluate field-level conditional rules reactively in the form renderer via the canonical @objectstack/formula ExpressionEngine — the same dialect the server enforces (requiredWhen in rule-validator, readonlyWhen in stripReadonlyWhenFields) — so the client UX and the persisted verdict always agree. - core: evalFieldPredicate / resolveFieldRuleState (zero-React, fail-open) - types: FormField gains visibleWhen/readonlyWhen/requiredWhen (+ deprecated conditionalRequired alias) - components: form renderer watches the live record, gates visible/readonly/ required per field - plugin-form: ObjectForm carries the rule props through from object metadata - 16 unit tests 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
|
…36 + skill (B2) Completes B2 client conditional rules: - form renderer seeds every declared field to null before overlaying defined watched values, so a visibleWhen/etc. predicate referencing a not-yet- registered field compares against null instead of faulting on a missing key (CEL "No such key") and failing open — mirrors the server's full-record merge - core: unit test locking the missing-key fail-open contract (17 tests) - e2e/live: field-conditional-rules.spec — drives Invoice Status through paid/sent/draft and asserts paid_on visibility, tax_rate lock, issued_on required all re-gate reactively (passes in a fresh context) - docs: ADR-0036 (field-level conditional rules) + objectui skill schema-expressions guide section Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
What
Client-side enforcement of field-level conditional rules so a form field can be conditionally shown/hidden (
visibleWhen), made read-only (readonlyWhen), or made required (requiredWhen) based on a CEL predicate over the live record. Evaluated reactively as the user types.This is the client half of B2. The server half (framework PR #1649) enforces
requiredWhenin the rule-validator and stripsreadonlyWhenwrites instripReadonlyWhenFields. The showcase example lives in a framework PR (see below). See ADR-0036.Why delegate to
@objectstack/formulaThe point of dual-side rules is that the client UX and the persisted server verdict agree. The client evaluates with the exact same engine + dialect the server uses —
@objectstack/formula'sExpressionEngine(CEL via@marcbachmann/cel-js) — rather than a parallel evaluator, so there is zero drift risk. The package is browser-safe (deps:@marcbachmann/cel-js+@objectstack/spec, which@object-ui/corealready depends on).Changes
evalFieldPredicate+resolveFieldRuleState— zero-React, fail-open (a broken/absent predicate never hides a field, blocks submit, or locks a field). Staticrequired/readonlyis a floor a FALSE predicate can't weaken.FormFieldgainsvisibleWhen/readonlyWhen/requiredWhen(+@deprecated conditionalRequiredalias).visible/readonly/requiredper field. It seeds every declared field tonullbefore overlaying defined watched values, so a predicate referencing a not-yet-registered field compares againstnullrather than faulting on a missing CEL key (mirrors the server's full-record merge).ObjectFormcarries the rule props through from object metadata.Tests
packages/core/.../fieldRules.test.ts) — predicate eval, object form,previous.*, fail-open, missing-key contract, alias precedence, static-flag floor.e2e/live/field-conditional-rules.spec.ts— drives the showcase Invoice Status through paid/sent/draft and assertspaid_onvisibility,tax_ratelock, andissued_onrequired all re-gate reactively. Passes (full live suite 11/11 green).Docs
docs/adr/0036-field-conditional-rules.mdskills/objectui/guides/schema-expressions.md— new CEL field-rules section (distinguishing the data-model CEL tier from the${}/Onwidget tier).🤖 Generated with Claude Code