Skip to content

feat: unify dynamic expression APIs under Expr<T>#127

Merged
ladparth merged 19 commits intomainfrom
feat/expr-api-simplification
Apr 15, 2026
Merged

feat: unify dynamic expression APIs under Expr<T>#127
ladparth merged 19 commits intomainfrom
feat/expr-api-simplification

Conversation

@ladparth
Copy link
Copy Markdown
Contributor

Description

Unifies all dynamic expression APIs under a single Expr<T> type, replacing the fragmented DynamicValue, VisibilityCondition, and resolveDynamicValue/evaluateVisibility helpers. Introduces inline JS functions as a first-class expression type — the "escape hatch" for non-JSON-serializable schemas requested in #110.

Also introduces FormRegistries as a unified container for all runtime registries (fields, validators, resolvers, fns), replacing the scattered registry, customValidators, and optionResolvers props. Registry merging is now handled correctly at the framework layer — global FormProvider registries are deep-merged with form-level overrides, with form-level keys winning per sub-registry.

Key Changes

Core (form-core)

  • Introduce Expr<T> unified expression system replacing DynamicValue and VisibilityCondition
  • Add $text node for string interpolation ("Hello ${/firstName}")
  • Add $when/$then/$else node for conditional branching (ternary)
  • Add $fn node for calling named functions from registries.fns
  • Add inline JS function support: condition: ({ data, context }) => ...
  • Introduce ExprContext with data and context properties
  • Add resolveExpr as the single evaluation entry point
  • Fix InferType for empty-name primitive arrays to produce flat arrays
  • Deprecate evaluateVisibility, resolveDynamicValue, and old context types

React Adapter (form-react)

  • Introduce FormRegistries container for fields, validators, resolvers, fns
  • Add registries prop to FormProvider, Form, RenderFields, FieldRenderer, and useForm
  • Add mergeRegistries utility — deep per-sub-registry merge, form-level keys override global
  • Normalize deprecated registry, customValidators, optionResolvers props into registries at entry points (FieldRenderer, RenderFields, FormProvider, useForm) — nothing deprecated leaks downstream
  • Fix FormProvider clobbering outer context when registries is undefined
  • Deprecate registry, customValidators, and optionResolvers top-level props

Docs / Web (apps/web)

  • Update all docs to use registries API
  • Update FormProvider in global providers to registries={{ fields: registry }}
  • Update registry components (form.tsx, array.tsx, collapsible.tsx, tabs.tsx) to use resolveExpr and registries
  • Update country-state-form example to use registries.resolvers

Type of change

  • feat (New feature)
  • fix (Bug fix)
  • refactor (Refactoring code without changing behavior)

Related Issues

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
buzzform Ready Ready Preview, Comment Apr 15, 2026 0:39am

@ladparth ladparth changed the title feat(form-core,form-react): unify dynamic expression APIs under Expr<T> feat: unify dynamic expression APIs under Expr<T> Apr 15, 2026
@ladparth ladparth merged commit d4302d9 into main Apr 15, 2026
3 checks passed
@ladparth ladparth deleted the feat/expr-api-simplification branch April 15, 2026 12:41
@github-actions github-actions Bot mentioned this pull request Apr 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] Allow passing async functions to the form schema

1 participant