Core Concepts

Attributes & Utilities

Attributes are the foundation for visual characteristics and properties, that can be defined and added to a Mix. In Flutter we say "Everything is a widget", so in Mix.

Everything is an Attribute

To make interaction with Attributes easier we have Utility functions. That allow for more control over how an attribute is composed.

Lets take the following example.

Mix(height(100));

This is defining a Mix with the box height attribute of 100. However height() is a Utility that allows us to compose an Attribute.

Similar to this

height(double value) => BoxAttribute(height: value);

With that in mind you can think of the following being equivalent.

Mix(height(100))
// is equivalent to
Mix(BoxAttribute(height: 100))

As you can see Utilities are not required for comsing Mixes however, make a cleaner API possible and overall better development experience.

Mixable Widgets

These are the widget primitives that allow a Mix to be rendered. At first sight it might look like these widgets are doing a lot, however they are just wrapping basic Flutter widgets and allowing their visual properties to be defined through a Mix.

The most basic widget primitive. Box is not like a Container, "Box is a Container". That means you can think of all BoxAttributes as Container properties.

You might think Box is like a Container, but that would be wrong. Box is a Container.

That means that this:

Box(mix:Mix(height(100)));

will become the following

Container(height: 100);

You can start to think as Utilities as shortcuts to defining visual properties.

Box(mix:Mix(rounded(100)));

will become the following

Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(10),
),
),
)

Decorators

Decorators allow to extend Mix functionality by providing an easy way to define it's Widget composition tree. This allows to keep the a lean core, and give complete control over layout, attribute, and widgets not supported by our MixableWidgets.

As an example we will provide the implementation for our scale attribute. The Container does not provide a scale property, so the implementation is done by wrapping a Container with the Transform widget.

Transform.scale(
scale: 0.5,
child: Container(
child: const Text('Half sized box'),
),
)

Since Box is a Container it also does not have a scale property. However by using a Decorator we can accomlish the same effect.

Box(mix: Mix(scale(0.5)));

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 Pressable triggers the hover state.

final style = Mix(
width(750),
height(50),
rounded(10),
textStyle($button),
bgColor($primary),
textColor($onPrimary),
hover(
bgColor($primary),
textColor($onPrimary),
),
);
Pressable(
mix: style,
child: const TextMix('Button'),
);

Some other examples of pre-configured Variants are dark() and focus(). Variants can be extremely powerful, and allow you to create consistent variations of your Widgets.

Directives

Allow you to transform/modify Widget properties by defining them as an Attribute. A great example of this would be the text directives.

As an example you are able to change the case of a TextMix by using a directive.

final style = Mix(
upperCase(),
);
const TextMix('Click Here', mix: style),

In the above example Click Here becomes CLICK HERE

Design Tokens

Tokens allow to define visual properties like colors, text styles, and spacing that can be consistently applied across all your widgets.

The most important difference between defining a design token in Mix vs. a constant is that Mix allows you to define context reference values that will be used on build time.