Skip to content

feat(mix): complete widget modifier config APIs - #1054

Merged
leoafarias merged 2 commits into
mainfrom
docs/modifier-config-api-plan-v1
Sep 21, 2026
Merged

leoafarias merged 2 commits into
mainfrom
docs/modifier-config-api-plan-v1

Conversation

@leoafarias

Copy link
Copy Markdown
Collaborator

Related issue

None. Implements the proposal from #1053, which this PR supersedes.

Description

Every built-in modifier now has both a WidgetModifierConfig factory and a matching fluent chain method, so callers no longer need .modifier(SomeModifierMix(...)) to reach a first-party modifier. modifier / modifiers remain the entry points for custom modifiers.

The audit that motivated this found two kinds of gap:

API Factory Chain method This PR
mouseCursor missing missing adds both
scrollView missing missing adds both
skew exists missing adds chain method
defaultIcon exists missing adds chain method
iconTheme exists missing adds chain method
box exists missing adds chain method
reset exists missing adds chain method

Purely additive. Every new member delegates to an existing factory and merge, so modifier ordering, merge keys, null/default handling, rendering, and animation behavior are unchanged. No existing signature changed and no consumer migration is needed.

final style = BoxStyler().wrap(.mouseCursor(SystemMouseCursors.click));

final wrappers = WidgetModifierConfig.opacity(0.8)
    .mouseCursor(SystemMouseCursors.click)
    .scrollView(scrollDirection: Axis.horizontal);

A note on reset()

The chained reset() is merge(WidgetModifierConfig.reset()), which collapses to an empty modifier list rather than retaining the reset marker. So it clears the modifiers accumulated in that configuration only — merging the result into another configuration no longer clears that one:

base.merge(other.reset());                      // base's modifiers survive
base.merge(WidgetModifierConfig.reset());       // base's modifiers are cleared

That is pre-existing merge behavior, not something introduced here. It is characterized in tests and documented on the method, with a pointer to the factory for the merge-surviving case. Redesigning the reset algorithm was deliberately left out of scope.

Changes

  • packages/mix/lib/src/modifiers/widget_modifier_config.dart: mouseCursor and scrollView factories + chain methods; chain methods for skew, defaultIcon, iconTheme, box, reset. Dartdoc on the new entry points, with the reset() semantics spelled out.
  • packages/mix/test/src/modifiers/widget_modifier_config_test.dart (new, 25 tests): factory ↔ explicit-modifier parity; full option forwarding for scrollView and iconTheme including omitted-stays-null; chain ↔ merge parity; contextual dot shorthand through a Styler's wrap; same-type merge without duplication; source-configuration immutability; custom orderOfModifiers surviving chaining; six reset characterization tests. Two widget pumps assert the real MouseRegion and SingleChildScrollView are produced.
  • packages/mix/CHANGELOG.md: entry under the unreleased 2.2.0-beta.5 section.
  • guides/api-composition-guidelines.md: quick-reference lines and a worked widget-modifier example. Both snippets were compiled against the package before being added.
  • guides/modifier-config-api-plan.md: removed, now that the plan it described is implemented.

Review Checklist

  • Testing: melos run gen:build (no generation drift), melos run analyze (Dart + DCM), and melos run ci all pass. flutter test test/src/modifiers is green at 498 tests, 25 of them new.
  • Breaking Changes: None. Additive only; no existing factory or chain-method signature changed.
  • Documentation Updates: Dartdoc on the new members, a CHANGELOG entry, and the composition guide.
  • Website Updates: Not included. The btwld/mix-docs site and the DartPad examples should keep the existing .modifier(...) form until these APIs land in a published release.

Additional Information (optional)

Pre-existing defect found while testing, deliberately not fixed here. MouseCursorModifier and ScrollViewModifier are absent from _defaultOrder, so reorderModifiers appends them in chaining order and always places them innermost:

scrollView().padding().mouseCursor()  ->  Padding, ScrollView, MouseCursor
mouseCursor().padding().scrollView()  ->  Padding, MouseCursor, ScrollView

In practice .scrollView(...).padding(...) puts the padding outside the scroll view, and the two modifiers' relative order depends on call order. This predates the PR, but it matters more now that both are first-class APIs. Related and also pre-existing: the defaultModifier lerp-fallback map omits MouseCursorModifier, ScrollViewModifier, ClipRectModifier, ShaderMaskModifier, DefaultTextStylerModifier, and BoxModifier, so animating those from absent to present snaps at t = 0.5 instead of lerping. Both are worth a separate follow-up.

The branch name still carries the docs/ prefix from the plan-only branch this work grew out of; the change itself is a feat.

Add `mouseCursor` and `scrollView` as both `WidgetModifierConfig` factories
and chain methods, and add the chain methods their factories were missing for
`skew`, `defaultIcon`, `iconTheme`, `box`, and `reset`. Every built-in
modifier is now reachable without `.modifier(SomeModifierMix(...))`, while
`modifier`/`modifiers` stay the entry points for custom modifiers.

All new members delegate to the existing factories and `merge`, so modifier
ordering, merge keys, null handling, rendering, and animation are unchanged.

Chained `reset()` collapses to an empty modifier list, so it clears only the
modifiers accumulated in that configuration; the `WidgetModifierConfig.reset()`
factory is still required when the reset must survive a later merge. Both
behaviors are characterized in tests and documented on the method.

Remove guides/modifier-config-api-plan.md now that the plan is implemented.
@leoafarias
leoafarias merged commit e55584a into main Sep 21, 2026
7 checks passed
@leoafarias
leoafarias deleted the docs/modifier-config-api-plan-v1 branch September 21, 2026 00:48
leoafarias added a commit that referenced this pull request Sep 21, 2026
Move the WidgetModifierConfig notes from #1054 out of the published 2.2.0-beta.5 section into a new mix 2.2.0-beta.6 section, and promote the mix_generator @MixWidget qualifier fix from #1050 to 2.2.0-beta.4. Changelogs and pubspec versions only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant