Skip to content

Experiment: ValidationMode as a strategy class - #107

Closed
KamilSztandur wants to merge 3 commits into
after-first-unfocusfrom
validation-strategy
Closed

KamilSztandur wants to merge 3 commits into
after-first-unfocusfrom
validation-strategy

Conversation

@KamilSztandur

Copy link
Copy Markdown
Collaborator

What this is

A sizing exercise, not a proposal to merge. It builds the idea from the comment on #103 (ValidationMode as a strategy, open for users' own modes) on top of the fourth mode, so the diff shows exactly what the idea adds beyond the enum.

What changes

  • ValidationMode is a final class with the four modes as constants, values and name kept, and ValidationMode.custom(name, fn) for a mode of your own.
  • A strategy implements ValidationStrategy.validatesOn(ValidationContext). The context carries the event and whether the user has left the field since editing it. It carries no status and no errors on purpose: both are erased by every edit and by a debounced round, so a strategy reading them would disarm itself as the user starts fixing the value.
  • The untouched-field rule stays in the field, outside any strategy: a custom mode cannot validate a field the user never edited.
  • ValidationEvent and ValidationContext become public API. Both were @internal.
  • Existing call sites compile unchanged: constructor, setValidationMode, comparisons. Exhaustive switch over the modes needs a wildcard, the same break the fourth enum value already causes.

Size

Area Lines
Package (lib/) about 100 added, 60 removed, 3 files
Tests 54 added, one new group
Docs and changelog about 50 lines

Not done here: the skill, the README table, the FAQ, and the equality story for custom modes (two custom calls are never equal, so a user who recreates one in build drops the round in flight; the doc says "keep one instance" and leaves it there).

Why the enum still wins

The code is small. The cost is what becomes a promise: the event model and the context are frozen as public API, and every future bit (a submit flag, for example) is a compatibility decision. Going from the enum to this class later is as source-compatible as doing it now, so keeping the enum closes no doors.

🤖 Generated with Claude Code

KamilSztandur and others added 3 commits October 12, 2026 17:01
A common ask: no error while the user types an email for the first
time, validate when they leave the field, and from then on validate
every keystroke so the error disappears as soon as the value is fixed.
Neither onUnfocus nor onUserInteraction does this on its own.

ValidationMode.afterFirstUnfocus is the onUnfocus row of the gate until
the field is first left after an edit, and the onUserInteraction row
from then on. The field remembers that first unfocus in one bit, set by
the event and cleared only by reset(). The gate still reads no status.
validate() from a submit button does not count as the first unfocus,
and leaving a field the user never edited does not either.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
With four modes the segmented button no longer fits a phone, and
Flutter broke the labels mid-word ("afterFir / stUnfoc / us"). It
already did that to onUserInteraction with three. The row now keeps
its full width where it fits and scrolls horizontally where it does
not, in both copies of the demo.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
What Albert's proposal on #103 would cost, built on top of the fourth
mode so the two can be compared. ValidationMode becomes a final class
with the four modes as constants and ValidationMode.custom for a mode
of your own. A strategy sees a ValidationContext: the event and whether
the user has left the field since editing it, never the status or the
errors. The untouched-field rule stays in the field, outside any
strategy. ValidationEvent becomes public API.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@KamilSztandur

Copy link
Copy Markdown
Collaborator Author

Folded into #103, as decided: the fourth mode and the class with custom() ship together.

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.

1 participant