Releases
v4.0.0
Compare
Sorry, something went wrong.
No results found
4.0.0 (2026-09-24)
⚠ BREAKING CHANGES
lov: ILovConfiguration<TItem, TValue> gained a GetByKeyProvider property. A custom class implementing that interface must add it (returning null keeps the previous behaviour). Configurations built through LovBuilder are unaffected.
lov: MudBlazorLovFieldComponent and FluentUILovFieldComponent gained a TKey type parameter (<TModel, TValue, TKey, TItem>), with TValue now the field's bound type. Code that renders these components directly by their old three-argument generic shape must add the key type; fields configured through .AsLov(...) / .AsMultiSelectLov(...) are unaffected.
lov: AsMultiSelectLov<TModel, TValue, TItem>'s configure parameter changed from Action<LovBuilder<TModel, IEnumerable<TValue>, TItem>> to Action<LovBuilder<TModel, TValue, TItem>>, so WithKey now takes the scalar item key. Callers with an explicitly-typed configure lambda must update the type; inferred lambdas are unaffected.
core: IFormConfiguration<TModel>.ShowValidationSummary now defaults to false (it was true, but had no effect). A form now renders a validation summary only after opting in with .ShowValidationSummary(). IFormConfiguration<TModel>.ShowRequiredIndicator, .RequiredIndicator, FormBuilder<TModel>.ShowRequiredIndicator(bool, string) and FormLayout.Horizontal are [Obsolete]. A consumer that builds with warnings as errors gets CS0618 until it moves to .WithNativeRequired() / FormLayout.Grid or suppresses the warning locally.
core: a nested field's FieldName is now its full dotted path (Shipping.Value), not its last member name (Value). This is visible through GetRequiredFields, OnFieldChanged, validation message keys (FieldIdentifier), DependsOn/group membership keys, and DOM ids built from the field name. Single-level fields are unchanged.
security: EncryptField now fails closed. An expression that does not resolve to a string property, or a path that cannot be resolved, throws ArgumentException at configuration time instead of being silently skipped. Nested members (x => x.Address.City) are now actually encrypted and stored under their full dotted path.
core: FormDiagnosticScope and DiagnosticLog moved from FormCraft.ForMudBlazor to FormCraft.Diagnostics (core). Code that references them by the old namespace must update its using directive. No forwarding shim is provided.
core: move the UI-agnostic adapter machinery into core (#279 ) (#289 )
core: expose Validators as IReadOnlyList and require AddValidator (#245 )
lov: WithDisplay(Expression<Func<TItem,string>>) is removed. Pass a lambda directly, or expr.Compile() if you hold an Expression.
Features
core: localize default validation messages (#354 ) (#361 ) (6a9a2dc )
demo: redesign the demo site around code beside the live form (#390 ) (60766d3 )
demo: redesign the demo site around the code-to-form binding (#268 ) (679e0a2 )
fluentui: add a FormCraft.ForFluentUI adapter for Fluent UI Blazor v5 (#260 ) (#261 ) (713e358 )
fluentui: bring the Fluent UI adapter to parity with MudBlazor (#278 ) (#291 ) (6f6acaf )
mudblazor: add a typed builder method for the native required opt-in (#204 ) (#236 ) (4210be4 )
mudblazor: add a typed WithMask builder for text field masks (#265 ) (#273 ) (61e6445 )
mudblazor: announce required fields without the HTML5 required attribute (#263 ) (#353 ) (3341705 )
mudblazor: announce required file-upload fields to assistive technology (#262 ) (#270 ) (ba02aad )
mudblazor: give numeric adornments a typed click handler (#215 ) (#244 ) (8a03598 )
mudblazor: make ShrinkLabel configurable per field and per form (#177 ) (#178 ) (7a7dc30 )
mudblazor: warn when a mask blanks a stored value (#266 ) (#274 ) (1ea5425 )
mudblazor: warn when ShrinkLabel=false cannot be honoured (#181 ) (#183 ) (b22d05d )
mudblazor: warn when the password toggle displaces a configured adornment (#219 ) (#243 ) (eccbf2d )
Bug Fixes
adapters: custom template no longer renders nothing for a non-property field (#330 ) (#387 ) (0d378af )
adapters: make Add/Remove inert and diagnosable on an unreadable collection binding (#433 ) (#439 ) (a8adaf5 )
adapters: stop a null-intermediate collection binding from crashing render (#419 ) (#427 ) (1bd2dc3 )
adapters: warn once on an unwritable nested collection item edit (#450 ) (#451 ) (e774a46 )
adapters: write back through the field's compiled expression for custom templates (#413 ) (20d80c3 )
build: stop Clean deleting the build output it is running from (#310 ) (#368 ) (7e3f9e7 )
core: build CollectionSetter from the full nested member chain (#420 ) (#424 ) (9bac0ce )
core: evaluate DisabledCondition on render, mirroring VisibleWhen (#476 ) (#479 ) (e51c9ef )
core: honour or retire the inert form-level settings (#457 ) (8d75085 )
core: keep collection validation messages consistent with the rendered form (#342 ) (#379 ) (69b56c4 )
core: qualify collection field identity by its full nested path (#428 ) (#434 ) (e87756f )
core: qualify scalar field identity by its full nested path (#437 ) (37cb742 )
core: resolve DisabledCondition in the core stub field renderers (#483 ) (#489 ) (f9df972 )
core: share one security pipeline across both adapters (#321 ) (#402 ) (e1488a1 )
core: stamp identifiers a validation pass writes fresh (#445 ) (#446 ) (a7e74ec )
core: stamp valid collection cells and skip hidden fields on write (#447 ) (#452 ) (430c664 )
core: stop an unreadable nested binding from crashing render or validation (#397 ) (#403 ) (45d7c0d )
core: stop an unreadable nested collection binding from crashing validation (#414 ) (f52faa0 )
core: stop FieldValueGetterCache swallowing genuine accessor faults and cancellation (#425 ) (#438 ) (6f6aaee )
core: validate each collection item field once per pass (#329 ) (#331 ) (65944e5 )
demo: allow pinch-zoom in the Fluent UI demo (#341 ) (#360 ) (af2900e )
demo: correct ARIA state, disposal and fade-in regressions (#285 ) (#295 ) (3dd997c )
demo: guard every timed re-render against component disposal (#315 ) (#323 ) (8557ce3 )
demo: make every demo page readable and fill the gallery (#405 ) (e5260fc )
demo: stop nesting cards in the form panel and give wide forms room (#411 ) (36e18c3 )
fluentui: bind numeric bounds explicitly so a dropped bound is dropped (#348 ) (#382 ) (d4952cd )
fluentui: clear TooManyFilesError on a multiple-file-upload config swap (#416 ) (#421 ) (bd46189 )
fluentui: focus the collection controls' own buttons, not their wrapper spans (#383 ) (#399 ) (f073d88 )
fluentui: keep keyboard focus after collection controls unmount (#337 ) (#377 ) (59ea837 )
fluentui: key collection rows on a weak per-item token (#401 ) (#410 ) (c73d088 )
fluentui: re-read a field's configuration when the rendered field changes (#335 ) (#336 ) (d3af1ff )
lov: bind AsMultiSelectLov's WithKey to the scalar per-item key (#467 ) (70fa17c )
lov: let WithDisplay and WithKey accept a plain lambda (#180 ) (#182 ) (fa88097 )
lov: resolve multi-select LOV component TValue from the field's bound type (#480 ) (0780e08 )
lov: WithDataSource(collection) honors search/sort/context filters (#472 ) (a8f0561 )
mudblazor: announce required fields to assistive technology (#199 ) (#254 ) (e8e3586 )
mudblazor: bind a configured mask on both render paths (#211 ) (#253 ) (8484dba )
mudblazor: bind DisabledWhen to MudBlazor file upload components (#487 ) (0343e59 )
mudblazor: bind factory masks whose pattern is computed lazily (#317 ) (#366 ) (75ebb81 )
mudblazor: clear a multiple-file upload to an empty list, notifying once (#319 ) (#376 ) (0828678 )
mudblazor: closing one LOV chip removes only that item instead of clearing the whole selection (#475 ) (0780e08 )
mudblazor: dedupe field diagnostics across component re-mounts (#304 ) (#309 ) (44d46ff )
mudblazor: drop the write-only _valueLookup cache from the autocomplete component (#404 ) (#415 ) (769ec49 )
mudblazor: focus Browse after clearing a file upload (#281 ) (#292 ) (da7d1dc )
mudblazor: forward a configured adornment to date item fields (#217 ) (#248 ) (b4b649f )
mudblazor: hide the upload's native file input and keep drops working (#456 ) (6d0de99 )
mudblazor: honour a configured Culture on numeric item fields (#218 ) (#247 ) (e31a7e6 )
mudblazor: honour Format and ShowSpinButtons on numeric fields (#208 ) (#240 ) (cefa8a8 )
mudblazor: invoke the adornment click handler passed to WithAdornment (#192 ) (#194 ) (92add18 )
mudblazor: judge the ShrinkLabel diagnostic on the rendered adornment (#212 ) (#241 ) (36dc2aa )
mudblazor: keep a password field masked when it also configures multiple lines (#207 ) (#232 ) (aea3e40 )
mudblazor: key collection rows on a per-item weak token (#334 ) (#400 ) (705a48b )
mudblazor: map number, date and time to their input types (#210 ) (#239 ) (6dcab2d )
mudblazor: mask password fields inside collection item forms (#189 ) (#196 ) (421eee3 )
mudblazor: move focus deliberately after a self-unmounting control (#318 ) (#324 ) (33102ff )
mudblazor: qualify the ShrinkLabel diagnostic key so scopes cannot collide (#242 ) (2d591c3 )
mudblazor: re-read a field's configuration when the rendered field changes (#298 ) (#308 ) (947a3a5 )
mudblazor: render a handler-less adornment as a plain icon, not a button (#216 ) (#224 ) (789acae )
mudblazor: render adornments on collection item fields (#184 ) (#188 ) (89f0dbc )
mudblazor: render adornments on numeric fields (#191 ) (#195 ) (7b3743f )
mudblazor: render each uploaded file once (#338 ) (#362 ) (e79abe4 )
mudblazor: render long, float, short and byte collection item fields (#209 ) (#246 ) (0c8be25 )
mudblazor: render novalidate on the form instead of applying it by script (#206 ) (#235 ) (c9b5047 )
mudblazor: report post-init and partially-discarded masked values (#283 ) (#293 ) (af5c605 )
mudblazor: stop emitting the HTML5 Required attribute on collection item fields (#190 ) (#193 ) (3bb3bde )
sanitize FieldName for CSS-safe DOM ids on nested fields (#449 ) (#453 ) (a47834f )
security: encrypt nested EncryptField members through their full path (#423 ) (5b9e5b3 )
security: key audit log entries by full nested path, not last member (#406 ) (#412 ) (2e4fcf8 )
security: redact nested audit keys by full path or last segment (#417 ) (#418 ) (bfc24df )
security: resolve EncryptField paths through inherited interface properties (#429 ) (#432 ) (864a071 )
upload: resolve constraints through one path in every upload component (#340 ) (#388 ) (c1606a0 )
validation: keep prior messages intact when ValidateModelAsync throws mid-pass (#440 ) (#441 ) (26ae1ff )
validation: stop message-store races in DynamicFormValidator (#443 ) (#444 ) (6052839 )
Performance
core: compile each field's value getter once (#269 ) (#286 ) (cdc9ec4 )
core: compile each field's value getter once per validation (#312 ) (#320 ) (320d689 )
core: remove per-render reflection from the field render path (#314 ) (#378 ) (1cae68e )
Refactor
build: give the results directory one definition (#339 ) (#359 ) (3556327 )
core: call the collection validator through a typed surface (#344 ) (#381 ) (bd725ba )
core: expose Validators as IReadOnlyList and require AddValidator (#245 ) (376866b )
core: move the UI-agnostic adapter machinery into core (#279 ) (#289 ) (e31cc39 )
core: share collection row identity tracking across adapters (#422 ) (#442 ) (7b5111c )
core: share diagnostics warning log and per-form latch across adapters (#398 ) (c0044cf )
core: share numeric type-default resolution between both adapters (#389 ) (#393 ) (aaa27e9 )
mudblazor: express the two diagnostic idioms once each (#284 ) (#294 ) (17e0dea )
mudblazor: render collection item fields through IFieldRendererService (#203 ) (#250 ) (5c66e29 )
You can’t perform that action at this time.