Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/mix/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
2 changes: 1 addition & 1 deletion packages/mix/lib/src/specs/box/box_spec.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/mix/lib/src/specs/stackbox/stackbox_spec.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/mix/lib/src/specs/text/text_spec.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions packages/mix/lib/src/style/mixins/decoration_style_mixin.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -39,9 +40,13 @@ mixin DecorationStyleMixin<T extends Mix<Object?>> {
return decoration(BoxDecorationMix.boxShadow([value]));
}

/// Sets multiple shadows
T shadows(List<BoxShadowMix> 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
Expand Down
11 changes: 8 additions & 3 deletions packages/mix/lib/src/style/mixins/shadow_style_mixin.dart
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -26,9 +27,13 @@ mixin ShadowStyleMixin<T extends Mix<Object?>> {
return decoration(BoxDecorationMix.boxShadow([shadow]));
}

/// Creates multiple box shadows from a list of BoxShadowMix
T boxShadows(List<BoxShadowMix> 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) {

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.

return decoration(BoxDecorationMix.create(boxShadow: Prop.mix(value)));
}

/// Creates box shadows from Material Design elevation level
Expand Down
11 changes: 8 additions & 3 deletions packages/mix/lib/src/style/mixins/text_style_mixin.dart
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -84,9 +85,13 @@ mixin TextStyleMixin<T extends Mix<Object?>> {
return style(TextStyleMix.fontFamilyFallback(value));
}

/// Sets text shadows
T shadows(List<ShadowMix> 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.
Expand Down
4 changes: 2 additions & 2 deletions packages/mix/test/src/specs/box/box_style_factory_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
});

Expand Down
4 changes: 2 additions & 2 deletions packages/mix/test/src/specs/box/box_style_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@ 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)));
});

Expand Down
6 changes: 3 additions & 3 deletions packages/mix/test/src/specs/text/text_style_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -525,9 +525,9 @@ 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);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,92 @@ void main() {
expect(boxShadowRef, isA<List<BoxShadow>>());
expect(boxShadowRef.runtimeType, equals(BoxShadowListRef));
});

test('BoxShadowToken.mix() returns BoxShadowListMixRef', () {
const boxShadowToken = BoxShadowToken('test.box.shadows.mix');
final mixRef = boxShadowToken.mix();

expect(mixRef, isA<BoxShadowListMixRef>());
expect(mixRef, isA<BoxShadowListMix>());
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<BoxDecoration>());
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);
});
});
}
8 changes: 5 additions & 3 deletions packages/mix_tailwinds/lib/src/tw_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
);
}

Expand Down Expand Up @@ -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)),
);
}

Expand Down Expand Up @@ -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(
Expand Down
Loading