From 779a3845107aa9a52be8003ba8c3177fd3383b88 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 12 Jun 2026 00:27:44 -0300 Subject: [PATCH 1/2] fix(mix): accept *ListMix on shadow styler methods so token refs work `BoxStyler().boxShadows(token.mix())` failed to compile because the styler methods took `List` 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) --- packages/mix/CHANGELOG.md | 10 +++ .../mix/lib/src/specs/box/box_spec.g.dart | 2 +- .../lib/src/specs/flexbox/flexbox_spec.g.dart | 2 +- .../src/specs/stackbox/stackbox_spec.g.dart | 2 +- .../mix/lib/src/specs/text/text_spec.g.dart | 2 +- .../style/mixins/decoration_style_mixin.dart | 11 ++- .../src/style/mixins/shadow_style_mixin.dart | 11 ++- .../src/style/mixins/text_style_mixin.dart | 11 ++- .../src/specs/box/box_style_factory_test.dart | 4 +- .../test/src/specs/box/box_style_test.dart | 4 +- .../flexbox/flexbox_style_factory_test.dart | 4 +- .../stackbox/stackbox_style_factory_test.dart | 4 +- .../specs/text/text_style_factory_test.dart | 2 +- .../test/src/specs/text/text_style_test.dart | 8 +- .../shadow_list_token_integration_test.dart | 87 +++++++++++++++++++ packages/mix_tailwinds/lib/src/tw_parser.dart | 8 +- 16 files changed, 144 insertions(+), 28 deletions(-) diff --git a/packages/mix/CHANGELOG.md b/packages/mix/CHANGELOG.md index 45c30ecd3d..87300b0fa9 100644 --- a/packages/mix/CHANGELOG.md +++ b/packages/mix/CHANGELOG.md @@ -1,3 +1,13 @@ +## Unreleased + +### Fixes + +- **Box / text shadow tokens through styler methods:** `BoxStyler.boxShadows`, `BoxStyler.shadows`, `FlexBoxStyler.shadows`, `StackBoxStyler.shadows`, and `TextStyler.shadows` now accept the `BoxShadowListMix` / `ShadowListMix` wrapper so design-token references (`BoxShadowToken('x').mix()`, `ShadowToken('y').mix()`) can be passed directly (#925). + +### Breaking changes + +- **Shadow styler methods now take a Mix wrapper instead of a raw list.** Update call sites that pass a literal list to wrap it: `BoxStyler().boxShadows([s1, s2])` → `BoxStyler().boxShadows(BoxShadowListMix([s1, s2]))`. The same applies to `.shadows(...)` on `BoxStyler` / `FlexBoxStyler` / `StackBoxStyler` and to `TextStyler.shadows(...)`. + ## 2.0.3 This release adds finer-grained control over scope inheritance and theming, and restores compatibility with newer Flutter SDKs. diff --git a/packages/mix/lib/src/specs/box/box_spec.g.dart b/packages/mix/lib/src/specs/box/box_spec.g.dart index 1b6c080de9..3f5162d664 100644 --- a/packages/mix/lib/src/specs/box/box_spec.g.dart +++ b/packages/mix/lib/src/specs/box/box_spec.g.dart @@ -233,7 +233,7 @@ class BoxStyler extends MixStyler factory BoxStyler.elevation(ElevationShadow value) => BoxStyler().elevation(value); factory BoxStyler.shadow(BoxShadowMix value) => BoxStyler().shadow(value); - factory BoxStyler.shadows(List value) => + factory BoxStyler.shadows(BoxShadowListMix value) => BoxStyler().shadows(value); factory BoxStyler.width(double value) => BoxStyler().width(value); factory BoxStyler.height(double value) => BoxStyler().height(value); diff --git a/packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart b/packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart index a2ebedd9d8..a30fa84994 100644 --- a/packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart +++ b/packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart @@ -170,7 +170,7 @@ class FlexBoxStyler extends MixStyler FlexBoxStyler().elevation(value); factory FlexBoxStyler.shadow(BoxShadowMix value) => FlexBoxStyler().shadow(value); - factory FlexBoxStyler.shadows(List value) => + factory FlexBoxStyler.shadows(BoxShadowListMix value) => FlexBoxStyler().shadows(value); factory FlexBoxStyler.width(double value) => FlexBoxStyler().width(value); factory FlexBoxStyler.height(double value) => FlexBoxStyler().height(value); diff --git a/packages/mix/lib/src/specs/stackbox/stackbox_spec.g.dart b/packages/mix/lib/src/specs/stackbox/stackbox_spec.g.dart index 5cb9f22b80..677d50a1b4 100644 --- a/packages/mix/lib/src/specs/stackbox/stackbox_spec.g.dart +++ b/packages/mix/lib/src/specs/stackbox/stackbox_spec.g.dart @@ -162,7 +162,7 @@ class StackBoxStyler extends MixStyler StackBoxStyler().elevation(value); factory StackBoxStyler.shadow(BoxShadowMix value) => StackBoxStyler().shadow(value); - factory StackBoxStyler.shadows(List value) => + factory StackBoxStyler.shadows(BoxShadowListMix value) => StackBoxStyler().shadows(value); factory StackBoxStyler.width(double value) => StackBoxStyler().width(value); factory StackBoxStyler.height(double value) => StackBoxStyler().height(value); diff --git a/packages/mix/lib/src/specs/text/text_spec.g.dart b/packages/mix/lib/src/specs/text/text_spec.g.dart index a2d6293fdf..43b0d7d579 100644 --- a/packages/mix/lib/src/specs/text/text_spec.g.dart +++ b/packages/mix/lib/src/specs/text/text_spec.g.dart @@ -309,7 +309,7 @@ class TextStyler extends MixStyler factory TextStyler.fontFamilyFallback(List value) => TextStyler().fontFamilyFallback(value); factory TextStyler.shadow(ShadowMix value) => TextStyler().shadow(value); - factory TextStyler.shadows(List value) => + factory TextStyler.shadows(ShadowListMix value) => TextStyler().shadows(value); factory TextStyler.fontFeatures(List value) => TextStyler().fontFeatures(value); diff --git a/packages/mix/lib/src/style/mixins/decoration_style_mixin.dart b/packages/mix/lib/src/style/mixins/decoration_style_mixin.dart index b362f7d5b5..4569d0d5f2 100644 --- a/packages/mix/lib/src/style/mixins/decoration_style_mixin.dart +++ b/packages/mix/lib/src/style/mixins/decoration_style_mixin.dart @@ -1,6 +1,7 @@ import 'package:flutter/widgets.dart'; import '../../core/mix_element.dart'; +import '../../core/prop.dart'; import '../../properties/painting/border_mix.dart'; import '../../properties/painting/border_radius_mix.dart'; import '../../properties/painting/decoration_image_mix.dart'; @@ -39,9 +40,13 @@ mixin DecorationStyleMixin> { return decoration(BoxDecorationMix.boxShadow([value])); } - /// Sets multiple shadows - T shadows(List value) { - return decoration(BoxDecorationMix.boxShadow(value)); + /// Sets multiple shadows. + /// + /// Accepts a [BoxShadowListMix] so that both literal lists + /// (`BoxShadowListMix([shadow1, shadow2])`) and design-token references + /// (`boxShadowToken.mix()`) can be passed. + T shadows(BoxShadowListMix value) { + return decoration(BoxDecorationMix.create(boxShadow: Prop.mix(value))); } /// Sets elevation shadow diff --git a/packages/mix/lib/src/style/mixins/shadow_style_mixin.dart b/packages/mix/lib/src/style/mixins/shadow_style_mixin.dart index 8d23f136ed..73b9d80391 100644 --- a/packages/mix/lib/src/style/mixins/shadow_style_mixin.dart +++ b/packages/mix/lib/src/style/mixins/shadow_style_mixin.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../../core/mix_element.dart'; +import '../../core/prop.dart'; import '../../properties/painting/decoration_mix.dart'; import '../../properties/painting/shadow_mix.dart'; @@ -26,9 +27,13 @@ mixin ShadowStyleMixin> { return decoration(BoxDecorationMix.boxShadow([shadow])); } - /// Creates multiple box shadows from a list of BoxShadowMix - T boxShadows(List value) { - return decoration(BoxDecorationMix.boxShadow(value)); + /// Sets multiple box shadows. + /// + /// Accepts a [BoxShadowListMix] so that both literal lists + /// (`BoxShadowListMix([shadow1, shadow2])`) and design-token references + /// (`boxShadowToken.mix()`) can be passed. + T boxShadows(BoxShadowListMix value) { + return decoration(BoxDecorationMix.create(boxShadow: Prop.mix(value))); } /// Creates box shadows from Material Design elevation level diff --git a/packages/mix/lib/src/style/mixins/text_style_mixin.dart b/packages/mix/lib/src/style/mixins/text_style_mixin.dart index f10111dedd..762029f7f9 100644 --- a/packages/mix/lib/src/style/mixins/text_style_mixin.dart +++ b/packages/mix/lib/src/style/mixins/text_style_mixin.dart @@ -1,6 +1,7 @@ import 'package:flutter/widgets.dart'; import '../../core/mix_element.dart'; +import '../../core/prop.dart'; import '../../properties/painting/shadow_mix.dart'; import '../../properties/typography/text_style_mix.dart'; @@ -84,9 +85,13 @@ mixin TextStyleMixin> { return style(TextStyleMix.fontFamilyFallback(value)); } - /// Sets text shadows - T shadows(List value) { - return style(TextStyleMix.shadows(value)); + /// Sets text shadows. + /// + /// Accepts a [ShadowListMix] so that both literal lists + /// (`ShadowListMix([shadow1, shadow2])`) and design-token references + /// (`shadowToken.mix()`) can be passed. + T shadows(ShadowListMix value) { + return style(TextStyleMix.create(shadows: Prop.mix(value))); } /// Sets a single text shadow. diff --git a/packages/mix/test/src/specs/box/box_style_factory_test.dart b/packages/mix/test/src/specs/box/box_style_factory_test.dart index cb299f2f47..7b27448b98 100644 --- a/packages/mix/test/src/specs/box/box_style_factory_test.dart +++ b/packages/mix/test/src/specs/box/box_style_factory_test.dart @@ -120,10 +120,10 @@ void main() { }); test('shadows', () { - final s = [ + final s = BoxShadowListMix([ BoxShadowMix(color: Colors.black, blurRadius: 10), BoxShadowMix(color: Colors.grey, blurRadius: 5), - ]; + ]); expect(BoxStyler.shadows(s), equals(BoxStyler().shadows(s))); }); diff --git a/packages/mix/test/src/specs/box/box_style_test.dart b/packages/mix/test/src/specs/box/box_style_test.dart index 183a746677..a7107f243d 100644 --- a/packages/mix/test/src/specs/box/box_style_test.dart +++ b/packages/mix/test/src/specs/box/box_style_test.dart @@ -251,10 +251,10 @@ void main() { }); test('shadows method sets multiple shadows', () { - final shadows = [ + final shadows = BoxShadowListMix([ BoxShadowMix(color: Colors.black, blurRadius: 5.0), BoxShadowMix(color: Colors.grey, blurRadius: 10.0), - ]; + ]); final boxMix = BoxStyler().shadows(shadows); expect(boxMix.$decoration, isNotNull); diff --git a/packages/mix/test/src/specs/flexbox/flexbox_style_factory_test.dart b/packages/mix/test/src/specs/flexbox/flexbox_style_factory_test.dart index f589b6d42b..1124c1b675 100644 --- a/packages/mix/test/src/specs/flexbox/flexbox_style_factory_test.dart +++ b/packages/mix/test/src/specs/flexbox/flexbox_style_factory_test.dart @@ -168,10 +168,10 @@ void main() { }); test('shadows', () { - final s = [ + final s = BoxShadowListMix([ BoxShadowMix(color: Colors.black, blurRadius: 10), BoxShadowMix(color: Colors.grey, blurRadius: 5), - ]; + ]); expect(FlexBoxStyler.shadows(s), equals(FlexBoxStyler().shadows(s))); }); diff --git a/packages/mix/test/src/specs/stackbox/stackbox_style_factory_test.dart b/packages/mix/test/src/specs/stackbox/stackbox_style_factory_test.dart index e4c73bdab3..88de2988f2 100644 --- a/packages/mix/test/src/specs/stackbox/stackbox_style_factory_test.dart +++ b/packages/mix/test/src/specs/stackbox/stackbox_style_factory_test.dart @@ -144,10 +144,10 @@ void main() { }); test('shadows', () { - final s = [ + final s = BoxShadowListMix([ BoxShadowMix(color: Colors.black, blurRadius: 10), BoxShadowMix(color: Colors.grey, blurRadius: 5), - ]; + ]); expect(StackBoxStyler.shadows(s), equals(StackBoxStyler().shadows(s))); }); diff --git a/packages/mix/test/src/specs/text/text_style_factory_test.dart b/packages/mix/test/src/specs/text/text_style_factory_test.dart index a7dc488964..ee153e243e 100644 --- a/packages/mix/test/src/specs/text/text_style_factory_test.dart +++ b/packages/mix/test/src/specs/text/text_style_factory_test.dart @@ -200,7 +200,7 @@ void main() { }); test('shadows', () { - final s = [ShadowMix(color: Colors.black, blurRadius: 4)]; + final s = ShadowListMix([ShadowMix(color: Colors.black, blurRadius: 4)]); expect(TextStyler.shadows(s), equals(TextStyler().shadows(s))); }); diff --git a/packages/mix/test/src/specs/text/text_style_test.dart b/packages/mix/test/src/specs/text/text_style_test.dart index c7019303cb..481eaf61c3 100644 --- a/packages/mix/test/src/specs/text/text_style_test.dart +++ b/packages/mix/test/src/specs/text/text_style_test.dart @@ -525,9 +525,11 @@ void main() { }); test('shadows utility works correctly', () { - final attribute = TextStyler().shadows([ - ShadowMix(color: Colors.black, offset: Offset(2, 2)), - ]); + final attribute = TextStyler().shadows( + ShadowListMix([ + ShadowMix(color: Colors.black, offset: Offset(2, 2)), + ]), + ); expect(attribute.$style, isNotNull); }); diff --git a/packages/mix/test/src/theme/tokens/shadow_list_token_integration_test.dart b/packages/mix/test/src/theme/tokens/shadow_list_token_integration_test.dart index 7d4283c46f..1d0324f129 100644 --- a/packages/mix/test/src/theme/tokens/shadow_list_token_integration_test.dart +++ b/packages/mix/test/src/theme/tokens/shadow_list_token_integration_test.dart @@ -127,5 +127,92 @@ void main() { expect(boxShadowRef, isA>()); expect(boxShadowRef.runtimeType, equals(BoxShadowListRef)); }); + + test('BoxShadowToken.mix() returns BoxShadowListMixRef', () { + const boxShadowToken = BoxShadowToken('test.box.shadows.mix'); + final mixRef = boxShadowToken.mix(); + + expect(mixRef, isA()); + expect(mixRef, isA()); + expect(isAnyTokenRef(mixRef), isTrue); + }); + + test('BoxStyler.boxShadows accepts BoxShadowToken.mix()', () { + const boxShadowToken = BoxShadowToken('test.box.shadows.boxShadows'); + + // Compiles and produces a styler with the token-backed shadow prop. + final styler = BoxStyler().boxShadows(boxShadowToken.mix()); + + expect(styler.$decoration, isNotNull); + }); + + test('BoxStyler.shadows accepts BoxShadowToken.mix()', () { + const boxShadowToken = BoxShadowToken('test.box.shadows.shadows'); + + final styler = BoxStyler().shadows(boxShadowToken.mix()); + + expect(styler.$decoration, isNotNull); + }); + + test('BoxStyler.shadows accepts a BoxShadowListMix literal', () { + final styler = BoxStyler().shadows( + BoxShadowListMix([ + BoxShadowMix(color: Colors.black, blurRadius: 5), + BoxShadowMix(color: Colors.grey, blurRadius: 10), + ]), + ); + + expect(styler.$decoration, isNotNull); + }); + + testWidgets( + 'BoxStyler.boxShadows resolves BoxShadowToken.mix() through MixScope', + (tester) async { + const boxShadowToken = BoxShadowToken('box.shadows.token-mix.resolved'); + final testBoxShadows = [ + const BoxShadow(color: Colors.black, blurRadius: 4), + const BoxShadow(color: Colors.grey, blurRadius: 2), + ]; + + await tester.pumpWidget( + MixScope( + tokens: {boxShadowToken: testBoxShadows}, + child: Builder( + builder: (context) { + final styler = BoxStyler().boxShadows(boxShadowToken.mix()); + final styleSpec = styler.resolve(context); + final decoration = styleSpec.spec.decoration; + + expect(decoration, isA()); + expect( + (decoration as BoxDecoration).boxShadow, + equals(testBoxShadows), + ); + + return const SizedBox.shrink(); + }, + ), + ), + ); + }, + ); + + test('TextStyler.shadows accepts ShadowToken.mix()', () { + const shadowToken = ShadowToken('text.shadows.mix'); + + final styler = TextStyler().shadows(shadowToken.mix()); + + expect(styler.$style, isNotNull); + }); + + test('TextStyler.shadows accepts a ShadowListMix literal', () { + final styler = TextStyler().shadows( + ShadowListMix([ + ShadowMix(color: Colors.black, offset: const Offset(1, 1)), + ]), + ); + + expect(styler.$style, isNotNull); + }); }); } diff --git a/packages/mix_tailwinds/lib/src/tw_parser.dart b/packages/mix_tailwinds/lib/src/tw_parser.dart index 605be8cfeb..ded4869f79 100644 --- a/packages/mix_tailwinds/lib/src/tw_parser.dart +++ b/packages/mix_tailwinds/lib/src/tw_parser.dart @@ -1063,7 +1063,8 @@ FlexBoxStyler _applyFlexShadow(FlexBoxStyler styler, TwValue value) { styler, value, applyElevation: (style, elevation) => style.elevation(elevation), - applyBoxShadows: (style, shadows) => style.boxShadows(shadows), + applyBoxShadows: (style, shadows) => + style.boxShadows(BoxShadowListMix(shadows)), ); } @@ -1211,7 +1212,8 @@ BoxStyler _applyBoxShadow(BoxStyler styler, TwValue value) { styler, value, applyElevation: (style, elevation) => style.elevation(elevation), - applyBoxShadows: (style, shadows) => style.boxShadows(shadows), + applyBoxShadows: (style, shadows) => + style.boxShadows(BoxShadowListMix(shadows)), ); } @@ -1363,7 +1365,7 @@ BoxStyler _applyBoxTextShadow(BoxStyler styler, TwValue value) { TextStyler _applyTextShadow(TextStyler styler, TwValue value) { final shadows = _resolveTextShadowMixes(value); if (shadows == null) return styler; - return styler.shadows(shadows); + return styler.shadows(ShadowListMix(shadows)); } TextStyler _applyPropertyToText( From 1234a849cdcff06a8b83c04047af8e7a94ef3b2e Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 12 Jun 2026 10:17:34 -0300 Subject: [PATCH 2/2] chore(mix): apply dart format Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/mix/test/src/specs/text/text_style_factory_test.dart | 4 +++- packages/mix/test/src/specs/text/text_style_test.dart | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/mix/test/src/specs/text/text_style_factory_test.dart b/packages/mix/test/src/specs/text/text_style_factory_test.dart index ee153e243e..ea1ad72c7e 100644 --- a/packages/mix/test/src/specs/text/text_style_factory_test.dart +++ b/packages/mix/test/src/specs/text/text_style_factory_test.dart @@ -200,7 +200,9 @@ void main() { }); test('shadows', () { - final s = ShadowListMix([ShadowMix(color: Colors.black, blurRadius: 4)]); + final s = ShadowListMix([ + ShadowMix(color: Colors.black, blurRadius: 4), + ]); expect(TextStyler.shadows(s), equals(TextStyler().shadows(s))); }); diff --git a/packages/mix/test/src/specs/text/text_style_test.dart b/packages/mix/test/src/specs/text/text_style_test.dart index 481eaf61c3..8ac5f2b015 100644 --- a/packages/mix/test/src/specs/text/text_style_test.dart +++ b/packages/mix/test/src/specs/text/text_style_test.dart @@ -526,9 +526,7 @@ void main() { test('shadows utility works correctly', () { final attribute = TextStyler().shadows( - ShadowListMix([ - ShadowMix(color: Colors.black, offset: Offset(2, 2)), - ]), + ShadowListMix([ShadowMix(color: Colors.black, offset: Offset(2, 2))]), ); expect(attribute.$style, isNotNull);