Variants
While building your design system you will find have the need to create certain variations of a Widget. This makes the design system more flexible and reusable, by leveraging shared visual properties between them.
In the following example hover()
is a Variant
that will be applied when a Pressable
triggers the hover state. The bgColor
and textColor
properties will be overridden with the new value when the variant applies
final style = Mix(
bgColor($primary),
textColor($onPrimary),
hover(
bgColor($primary),
textColor($onPrimary),
),
);
Pressable(
mix: style,
child: const TextMix('Button'),
);
Variants can be extremely powerful, and allow you to create consistent variations of your Widgets.
Usage
To use a variant, call it on a Mix
final mix = Mix(
dark(
textColor(Colors.white),
),
light(
textColor(Colors.black),
)
);
Conditional operators
The operators |
and &
can be used to add conditions to your mix:
|
: whether one of the variants apply
final mix = Mix(
padding(20.0),
(small | medium)( // Whether it's small OR medium
width(300),
height(400),
bgColor(Colors.white),
),
);
&
: when all of the variants apply
final mix = Mix(
padding(20.0),
(hover & press)( // When it's hovering AND pressing
textColor(Colors.black),
bold(),
),
);
The not
operator can also be called to execute the variant content only when the given
variant is not called. For example:
final mix = Mix(
(not(disabled))(
scale(1.2),
),
);
Variants catalog
Mix already has some Reactive Variants
defined which can be used to create responsive
Widgets.
Pressable
These are Variants
that will change based on different gestures and state of the
Pressable
Widget.
hover()
: Applies attributes on hover.focus()
: Applies attributes on focus.press()
: Applies attributes when pressing.disabled()
: Applies attributes when disabled.
Breakpoints
small()
: Applies attributes when the screen is at leastsmall
breakpoint.medium()
: Applies attributes when the screen is at leastmedium
breakpoint.large()
: Applies attributes when the screen is at leastlarge
breakpoint.
Breakpoints for these sizes can be configured in the MixTheme
:
MixTheme(
data: MixThemeData(
breakpoints: MixThemeBreakpoints(
small: 600, // cellphone
medium: 1240, // tablet
large: 1440, // desktop
),
),
child: ...,
),
Orientation
portrait()
: Applies attributes when the screen is in portrait orientation.landscape()
: Applies attributes when the screen is in landscape orientation.
Dark Mode
dark()
: Applies attributes when the theme is in dark mode.light()
: Applies attributes when the theme is in light mode.
State Holding
active()
: Applies attributes when the widget state is marked as activeinactive()
: Applies attributes when the widget state is marked as inactive
Text Styling
For widgets such as Dialogs, Cards and Modals, it's good to have titles and content.
title()
: Applies attributes when theTextMix
is marked as titleparagraph()
: Applies attributes when theTextMix
is marked as paragraph
final mix = Mix(
title(
titleCase(), // Makes the title uppercase
font(
weight: FontWeight.bold, // Makes the title bold
),
),
);
All other texts that are not marked as title
will not be touched.
Custom Variants
Mix gives you complete control of how to define your own Variants
and when they are
applied.
There are two types of Variants
that you are able to define: callable and context
variants.
Callable Variants
Can be called manually when they need to be applied. You can define a variant the following way.
const outlined = Variant('outlined');
final mix = Mix(
bgColor(Colors.black),
textColor(Colors.white),
outlined(
bgColor(Colors.transparent),
borderColor(Colors.black),
textColor(Colors.black),
),
);
You are then able to choose when to apply the variant based on your own logic.
Pressable(
mix: mix.withVariant(outlined),
onPressed: () {},
child: const TextMix('Outlined Button'),
);
You are also able to pass the variant through the variant
parameter on the
MixableWidget
constructor
Pressable(
mix: mix,
variant: outlined,
onPressed: () {},
child: const TextMix('Outlined Button'),
);
Context Variants
These are Variants
that have a method that defines when they should be applied based on
the BuildContext
. These will be applied automatically.
Here is an example implementation of the dark()
to understand how it works.
final dark = Variant(
'dark',
shouldApply: (BuildContext context) {
return Theme.of(context).brightness == Brightness.dark;
},
);