Skip to content

fix(mix): accept *ListMix on shadow styler methods so token refs work#932

Open
tilucasoli wants to merge 2 commits into
mainfrom
fix/box-shadow-token-mix
Open

fix(mix): accept *ListMix on shadow styler methods so token refs work#932
tilucasoli wants to merge 2 commits into
mainfrom
fix/box-shadow-token-mix

Conversation

@tilucasoli

@tilucasoli tilucasoli commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • BoxStyler().boxShadows(token.mix()) failed to compile because the shadow styler methods took List<BoxShadowMix> while BoxShadowToken.mix() returns a BoxShadowListMixRef (implements BoxShadowListMix, not the raw list type). The same gap blocked .shadows() on Box/Flex/StackBox stylers and TextStyler.shadows() with ShadowToken.
  • Change the shadow styler-mixin signatures to take the matching *ListMix wrapper and route through Prop.mix(value) so token refs flow end-to-end. Regenerated the affected .g.dart factory files; updated mix_tailwinds/tw_parser.dart for parity.
  • Breaking: literal-list callers wrap with BoxShadowListMix([...]) / ShadowListMix([...]). Logged under Unreleased in packages/mix/CHANGELOG.md.

Fixes #925.

What changed

File Change
packages/mix/lib/src/style/mixins/shadow_style_mixin.dart boxShadows(List<BoxShadowMix>)boxShadows(BoxShadowListMix)
packages/mix/lib/src/style/mixins/decoration_style_mixin.dart shadows(List<BoxShadowMix>)shadows(BoxShadowListMix)
packages/mix/lib/src/style/mixins/text_style_mixin.dart shadows(List<ShadowMix>)shadows(ShadowListMix)
packages/mix/lib/src/specs/{box,flexbox,stackbox,text}/*.g.dart Regenerated BoxStyler.shadows / FlexBoxStyler.shadows / StackBoxStyler.shadows / TextStyler.shadows factory signatures to match.
packages/mix_tailwinds/lib/src/tw_parser.dart Wrap parsed shadow lists with BoxShadowListMix(...) / ShadowListMix(...) before forwarding to the styler.
packages/mix/test/... Updated literal-list callsites in box/flexbox/stackbox/text styler tests.
packages/mix/test/src/theme/tokens/shadow_list_token_integration_test.dart New tests covering token.mix() and *ListMix literal flows.
packages/mix/CHANGELOG.md New "Unreleased" entry documenting the breaking change.

Note: IconStyler.shadows(List<ShadowMix>) is intentionally unchanged — that setter is derived from the IconSpec.shadows field, not from TextStyleMixin. It can be migrated in a follow-up if we want IconStyler to accept ShadowToken.mix() too.

Migration

// Before
BoxStyler().boxShadows([
  BoxShadowMix(color: Colors.black, blurRadius: 8),
  BoxShadowMix(color: Colors.grey, blurRadius: 4),
]);

// After (literal)
BoxStyler().boxShadows(BoxShadowListMix([
  BoxShadowMix(color: Colors.black, blurRadius: 8),
  BoxShadowMix(color: Colors.grey, blurRadius: 4),
]));

// After (token — the case that motivated this fix)
const cardShadow = BoxShadowToken('shadows.card');
BoxStyler().boxShadows(cardShadow.mix());

The same wrapping applies to BoxStyler.shadows(...), FlexBoxStyler.shadows(...), StackBoxStyler.shadows(...), and TextStyler.shadows(...).

Test plan

  • dart analyze . clean across all workspace packages (mix, mix_annotations, mix_generator, mix_lint, mix_tailwinds, mix_tailwinds_example).
  • flutter test in packages/mix: 2726/2726 passing.
  • flutter test in packages/mix_tailwinds: 322/322 passing.
  • New integration tests in shadow_list_token_integration_test.dart:
    • BoxShadowToken.mix() returns a BoxShadowListMixRef that satisfies the BoxShadowListMix interface.
    • BoxStyler().boxShadows(token.mix()) compiles and produces a styler with the token-backed shadow prop.
    • BoxStyler().shadows(token.mix()) (the DecorationStyleMixin path) compiles and produces a styler.
    • BoxStyler().shadows(BoxShadowListMix([...])) literal form works.
    • End-to-end MixScope resolve: boxShadowToken.mix() resolves to the configured List<BoxShadow> at render time.
    • TextStyler().shadows(shadowToken.mix()) and the ShadowListMix([...]) literal form for text shadows.

DCM was skipped locally (not installed in this environment). Should be re-checked by CI.

`BoxStyler().boxShadows(token.mix())` failed to compile because the styler
methods took `List<BoxShadowMix>` while `BoxShadowToken.mix()` returns a
`BoxShadowListMixRef` (which implements `BoxShadowListMix`, not the raw
list type). Same problem on `.shadows()` for Box/Flex/StackBox and on
`TextStyler.shadows()` with `ShadowToken`.

Change the shadow styler-mixin signatures to accept the matching
`*ListMix` wrapper and bypass the list-wrapping intermediate by calling
`Prop.mix(value)` directly, which preserves token refs end-to-end.

Breaking: literal-list callers wrap with `BoxShadowListMix([...])` /
`ShadowListMix([...])`.

Fixes #925

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@docs-page

docs-page Bot commented Jun 12, 2026

Copy link
Copy Markdown

To view this pull requests documentation preview, visit the following URL:

docs.page/btwld/mix~932

Documentation is deployed and generated using docs.page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@leoafarias leoafarias left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One verified medium-risk issue found around token-backed shadow list merging.

/// Accepts a [BoxShadowListMix] so that both literal lists
/// (`BoxShadowListMix([shadow1, shadow2])`) and design-token references
/// (`boxShadowToken.mix()`) can be passed.
T boxShadows(BoxShadowListMix value) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This handles direct BoxShadowToken.mix() usage, but it does not preserve the existing BoxShadowListMix merge semantics when the token-backed list is merged with a later literal list.

I verified this with a focused failing widget test:

final styler = BoxStyler()
    .boxShadows(token.mix()) // token resolves to BoxShadow(color: blue, blurRadius: 4)
    .boxShadows(BoxShadowListMix([BoxShadowMix(color: Colors.red)]));

The resolved shadow keeps the later red color, but blurRadius becomes 0.0 instead of preserving the token value 4. During resolution, Prop also logs that it cannot convert List<BoxShadow> to Mix<List<BoxShadow>>, so the token-resolved concrete list is skipped when Mix values are merged. The same issue reproduces for TextStyler.shadows with ShadowToken / List<Shadow>.

Existing shadow-list tests already establish index-wise in-place merge behavior for literal lists, so token-backed list sources should keep that behavior too. Please add conversion/normalization for List<BoxShadow> and List<Shadow> into BoxShadowListMix / ShadowListMix during mixed-source resolution, and add regression tests for token + literal list merges.

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.

'BoxShadowListMixRef' can't be assigned to the parameter type 'List<BoxShadowMix>'

3 participants