fix(mix): accept shadow token .mix() on raw-list styler methods (sentinel-style, non-breaking)#941
fix(mix): accept shadow token .mix() on raw-list styler methods (sentinel-style, non-breaking)#941tilucasoli wants to merge 8 commits into
Conversation
…entinel-style refs Make BoxShadowListMixRef / ShadowListMixRef also implement List<BoxShadowMix> / List<ShadowMix> so boxShadowToken.mix() and shadowToken.mix() can be passed directly to BoxStyler.boxShadows, BoxStyler.shadows, FlexBoxStyler.shadows, StackBoxStyler.shadows, and TextStyler.shadows. This mirrors the DoubleRef sentinel shim: the public signatures stay as raw lists, the token ref flows through as that type, and the styler detects it and routes it as a Mix so the TokenSource survives resolution. Unlike the *ListMix-wrapper approach, this keeps the styler signatures unchanged, so existing literal-list call sites, generated factories, and mix_tailwinds need no changes. Fixes #925. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… and token .mix() The example app under packages/mix/example shows applying box and text shadow lists two ways: as literal List<BoxShadowMix>/List<ShadowMix>, and via BoxShadowToken/ShadowToken `.mix()` references (BoxShadowListMix / ShadowListMix) resolved through MixScope — the flow enabled by this branch. Wires the in-repo mix / mix_annotations packages via dependency_overrides so the example resolves standalone, without requiring melos bootstrap. Includes a widget smoke test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…wListMix and token .mix()" This reverts commit bcd6f01.
Remove the deprecated .mix() helpers for ShadowToken and BoxShadowToken and related routing logic. Deleted Prop imports and the special-case branches in DecorationStyleMixin, ShadowStyleMixin, and TextStyleMixin that handled BoxShadowListMix/ShadowListMix token refs, simplifying shadow handling to use the standard call() refs. Update tests to remove assertions and integration tests that relied on the removed .mix() behavior. This cleans up token API surface and test coverage to match the simplified token reference model.
Introduce mix() helpers for ShadowToken and BoxShadowToken that return Mix-compatible refs and preserve Prop.token provenance. Update BoxDecorationMix and TextStyleMix to pass BoxShadowListMix/ShadowListMix through to Prop.mix when already a Mix so token sources aren't wrapped away. Clarify behavior in related style mixin comments. Add/extend tests to cover .mix() return types, styler acceptance, MixScope resolution, and token registry integration.
Import '../../core/prop.dart' into decoration, shadow, and text style mixins and shorten the doc comments for shadows/boxShadows methods by removing the verbose token-unwrapping explanation. This keeps the documentation concise and ensures the Prop symbol is available for these mixin files.
Remove the unused import '../../core/prop.dart' from decoration_style_mixin.dart, shadow_style_mixin.dart, and text_style_mixin.dart to clean up imports and eliminate unused-import warnings. No functional changes.
leoafarias
left a comment
There was a problem hiding this comment.
Review pass focused on the shadow list token behavior.
| boxShadow: boxShadow != null | ||
| ? Prop.mix(BoxShadowListMix(boxShadow)) | ||
| ? Prop.mix( | ||
| boxShadow is BoxShadowListMix |
There was a problem hiding this comment.
This branch currently blocks CI: with dcm analyze --fatal-warnings, boxShadow is statically List<BoxShadowMix>?, so DCM reports boxShadow is BoxShadowListMix and the following cast as unrelated. The same pattern in TextStyleMix fails too. Please route this through a DCM-safe helper or another preservation path so the token case survives without tripping analysis.
| final class ShadowListMixRef extends Prop<List<Shadow>> | ||
| with ValueRef<List<Shadow>> | ||
| implements ShadowListMix { | ||
| implements ShadowListMix, List<ShadowMix> { |
There was a problem hiding this comment.
Since this ref now implements the raw List<ShadowMix> type, it can be passed to every existing List<ShadowMix> constructor, not just TextStyler.shadows. Generated IconStyler(shadows:) and IconThemeModifierMix(shadows:) still do Prop.mix(ShadowListMix(shadows)), which wraps this token ref as a list item and then tries to iterate it during resolve. Please apply the same token-preserving path to those raw-list shadow constructors, including the generated source for IconStyler.
| // token-carrying [Prop]); pass it straight to [Prop.mix] so its token | ||
| // source is preserved instead of being wrapped into a fresh list. | ||
| shadows: shadows != null | ||
| ? Prop.mix( |
There was a problem hiding this comment.
This preserves pure token .mix() values, but merge resolution still loses token fields when a token list is chained with a literal list. In Prop.resolveProp, once sources include both TokenSource and MixSource, the resolved List<Shadow> must be converted back to Mix<List<Shadow>>; only individual Shadow/BoxShadow converters are registered today, so the token list is skipped. Please add list converters and tests for literal-to-token and token-to-literal merge order.
Summary
Same goal as #932 — let
BoxShadowToken('x').mix()/ShadowToken('x').mix()be passed directly to the shadow styler methods (BoxStyler.boxShadows,BoxStyler.shadows,FlexBoxStyler.shadows,StackBoxStyler.shadows,TextStyler.shadows) — but solved without changing any method signatures, so it is not a breaking change.This is the sentinel-value approach, modeled on how
DoubleReflets aMixToken<double>flow through plaindoubleAPIs: the public type stays natural, the token ref is-a that type, and it's detected and routed at the call site.Fixes #925.
The problem (recap of #925)
token.mix()returns aBoxShadowListMixRef(implementsBoxShadowListMix), but the styler method takes a rawList<BoxShadowMix>.Approach: sentinel-style refs (like
DoubleRef)DoubleRefis a sentinel-backed shim that implementsdouble, so aMixToken<double>flows through anydoubleparameter and is detected during prop construction. The signature never changes fromdouble.This PR applies the same idea to shadow lists:
BoxShadowListMixRefnow also implementsList<BoxShadowMix>(andShadowListMixRefimplementsList<ShadowMix>). The ref already extendsProp<List<BoxShadow>>and mixes inValueRef(whosenoSuchMethodguards the list members, which are never actually invoked). Sotoken.mix()now satisfies the existingList<BoxShadowMix>parameter type.List<BoxShadowMix>/List<ShadowMix>signatures. They detect a token ref (it's also aBoxShadowListMix/ShadowListMix) and route it throughProp.mix(...)so theTokenSourceis preserved; literal lists take the original path unchanged.What changed
packages/mix/lib/src/theme/tokens/token_refs.dartBoxShadowListMixRef/ShadowListMixRefnow alsoimplements List<BoxShadowMix>/List<ShadowMix>.packages/mix/lib/src/style/mixins/shadow_style_mixin.dartboxShadowsdetects aBoxShadowListMixtoken ref and routes it as a Mix; literal path unchanged. Signature unchanged.packages/mix/lib/src/style/mixins/decoration_style_mixin.dartshadows. Signature unchanged.packages/mix/lib/src/style/mixins/text_style_mixin.dartshadows. Signature unchanged.packages/mix/test/.../shadow_list_token_integration_test.dart.mix()through each styler, literal-list still works, andMixScopeend-to-end resolution.packages/mix/CHANGELOG.mdDifference from #932
boxShadows(BoxShadowListMix)boxShadows(List<BoxShadowMix>)— unchangedBoxShadowListMix([...]).g.dartfactoriesmix_tailwindsparserTest plan
dart analyze libclean (mix).dart analyze libclean (mix_tailwinds) — confirms nothing downstream needed changing.flutter testmix specs/style/theme suites: 545/545 passing.flutter testmix_tailwinds: 322/322 passing..mix()implements the raw list types, each styler accepts.mix(), literal lists still compile/work, andMixScoperesolvesboxShadowToken.mix()/shadowToken.mix()to the configured values at render time.🤖 Generated with Claude Code