An expressive way to effortlessly build design systems in Flutter.

Overview

mix

An expressive way to effortlessly build design systems in Flutter. Mix offers primitive building blocks to help developers and designers create beautiful and consistent UI.

Important

Mix is currently being used internally to build design systems in Flutter.
However, it is still in the experimental development stages.
Major APIs are expected to change until the 1.0 release.

Motivation & Goals

  • Creating consistent custom (non-material) UI in Flutter is difficult
  • Maintaining a design system is much harder than building it.
  • Visual attributes should be defined outside of a widget by a composable API shared across the design system.
  • Style consistently with a global theme
  • Respond to changing requirements quickly
  • Create adaptive layouts with ease
  • Material Theme compatible

Principles

  • Development efficiency is gained by the ease of use, consistency, and reusability, not coding speed.
  • Abstract Flutter API, and not modify its behavior.
  • Composability should be a priority. Mixes, Attributes, Widgets, etc.
  • Designer friendly (use simple standard semantics when possible)

Examples

Simple Mix

final squareMix = Mix(h(150), w(150));

Box(
    squareMix,
    child: Text('Square'),
);

// You can also use the following:
// This way has some downsides. More info soon...
squareMix.box(child:Text('Square'));

Composability

Extend Mixes

final cardMix = squareMix.mix(p(20), rounded(20), bgColor(Colors.white));

Override Mixes

final redCardMix = cardMix.mix(bgColor(Colors.red));

Combine Mixes

final elevationMix = Mix(
    shadowColor(Colors.black12),
    shadowBlur(4),
    shadowOffset(0, 2),
);

Box(
    Mix.combine(cardMix, elevationMix),
    child: Text('Card With Shadow'),
);

Conditional Mixes

// If you wan't to change the Mix depending on a condition
final conditonalMix = Mix.chooser(isSelected, dynamicMix, redCardMix);

Dynamic Mixes

If you want the card to change color when in dark mode you can use a dynamic attribute.

final dynamicMix = cardMix.mix(dark(bgColor(Colors.black)));

/// Now, when the app is on dark mode the card color will change to `black`.
Box(
    dynamicMix,
    child: Text('Dynamic Card'),
);

You can also leverage media query context values

final flexMix = Mix(gap(20), mainAxis.center);

// Adaptive gutter for your flex widgets using media query
final adaptiveFlexMix = flexMix.mix(
  mq.xs(gap(10)),
  mq.sm(gap(15)),
  mq.lg(gap(40)),
);

APIs

Documentation is currently in progress. For now you can find some of the available utilities here

Concepts

Here are some high-level concepts to understand how Mix works and to allow for you to get started.

Attributes

These are the features or characteristics of certain widgets. Most attributes map out to layout, visual widgets, or widget styling itself. Attributes are primitives which get translated into their Flutter API.

Dynamic Attributes

Attributes can be dynamic, which means they only are applied in case a condition is met. This allows for the creation of Atributes that can be used depending on the widget's BuildContext.

Utilities

These are classes whose primary purpose is providing a better API for Attributes.

Not required for building Mixes; however, make a cleaner API possible and overall better development experience.

Mixes

Combination or mix of Attributes. Mixes are passed to Widgets and translated into the widget's properties.

Mixes can be reused across multiple widgets and also combine, extended, and overridden.

Mixer Widgets

These are the building block for your design system. You can easily build new widgets that take advantage of Mixes; however, there are some primitives provided.

Box

Similar to a Container with some slight adjustments for a better development experience.

Flexbox

The equivalent of the Flex widgets (Flex, Row, Column). Allow for the use of flex Attributes, and wrap them in a Box to use box attributes for composability.

ColumnBox

The equivalent of the Column widget. Allows you to use Mix attributes to style and build custom text widgets. It is an abstraction of Flexbox, so it will also accept Box attributes.

RowBox

The equivalent of the Row widget. Allows you to use Mix attributes to style and build custom text widgets. It is an abstraction of Flexbox, so it will also accept Box attributes.

TextMix

The equivalent of the Text widget. Allows you to use Mix attributes to style and build custom text widgets.

IconMix

The equivlent to the Icon widget. Allows to use Mix attributes to style and build custom icon widgets.

License

This project is licensed under the MIT License - see the LICENSE file for details

Comments
  • Documentation: Organize dartdoc API output

    Documentation: Organize dartdoc API output

    dartdoc lumps all of the classes together without any distinction. Same with functions, constants, etc.

    These need to organized under header by type, category, etc.

    Not straightforward. Investigating.

    opened by rickbsgu 11
  • Gradient

    Gradient

    I'm investing in Mix and work on real designs so I'm trying to see how far I can implement a design lang. Thx!

    A linear 2 colors with start/end position would already cover most of the cases.

    Some very basics reflections:

    TopLeft, BottomRight gradient(tl, br, Colors.white, Colors.blue, .0, .72);

    vGradient(Colors.white, Colors.blue) top to bottom .0 => 1

    hGradient(Colors.white, Colors.blue) left to right .0 => 1

    opened by Solido 6
  • Pressable onHover, onMouseDown, onMouseUp callback

    Pressable onHover, onMouseDown, onMouseUp callback

    Hello mix team. Is there any way how to detect onHover, onMouseDown, onMouseUp from Pressable? I need to highlight specific a range of cells in a grid, starting from the one over which user has pressed mouse down and end on another where mouse up.

    Screenshot_select-area_20220321174135

    opened by VladimirCores 4
  • Widget: Pressable Component

    Widget: Pressable Component

    There is a need to create components that can be interacted with but easily styled. Right now this is not a problem as you can style all the components and wrap them in an InkWell or a GestureDetector, however, the creation of a Pressable component opens up some other possibilities.

    • Ability to provide styling for interactions, tap, hover, disabled etc.
    • Clean syntax for creating buttons and other pressable components using Mix
    enhancement widget 
    opened by leoafarias 4
  • Macro Benchmarks

    Macro Benchmarks

    Add macro benchmarks

    Addiontal reference

    • https://api.flutter.dev/flutter/flutter_test/benchmarkWidgets.html
    • https://api.flutter.dev/flutter/flutter_test/WidgetTester/pumpBenchmark.html
    • https://docs.flutter.dev/cookbook/testing/integration/profiling
    • https://github.com/flutter/flutter/blob/master/dev/benchmarks/macrobenchmarks/test/util.dart
    opened by bdlukaa 3
  • Shortcut for borderColor and others Mix properties

    Shortcut for borderColor and others Mix properties

    Would love to have:

    bgColor -> bgc
    border -> br
    borderColor -> brc
    borderWidth -> brw
    borderStyle -> brs
    rounded -> rd
    squared -> sq
    shadow -> sh
    

    and similar to others.

    opened by VladimirCores 3
  • Implement BoolExtension

    Implement BoolExtension

    Makes the following syntax possible:

    final mix = Mix(
      (true)( // [condition]
        bgColor(Colors.blue), // this is only executed if [condition] is true
      ),
    );
    
    opened by bdlukaa 3
  • Pressable freezes on press when onPressed: null

    Pressable freezes on press when onPressed: null

    Face a problem with Pressable - when click/press on the button with onPressed: null it freezes within press state.

    Mix (mix different colors):

      final mixButton = Mix(
        p(4),
        rounded(4),
        (hover)(
          bgColor(Colors.red.withOpacity(0.1))
        ),
        (press)(
          bgColor(Colors.red.lighten())
        ),
      );
    

    image

    opened by VladimirCores 3
  • Mix theme updates

    Mix theme updates

    Main updates

    • Removed .default getters where possible and replaced them with factory constructors
    • Removed .merge where it was irrelevant and replaced it with .copyWith
    • Replace ._ constructors with .raw constructors

    Other updates

    • Added equality and toString when relevant
    opened by bdlukaa 3
  • Initial doc changes

    Initial doc changes

    I've worked over primarily the 'Concepts' page, for starters. Also changed some of the header styling to something I think works better.

    Might have gotten carried away.

    Look it over and we can discuss.

    Do you have a git Project set up for this?

    thanx, rickb

    opened by rickbsgu 3
  • `when` variant

    `when` variant

    Fixes #102

    Basic usage:

    // in a stateful widget
    
    bool hasError = false;
    
    void fetch() {
      try {
        // perform the fetch
        setState(() => hasError = false);
      } catch (e) {
        // handle the error
        setState(() => hasError = true);
      }
    }
    
    final mix = Mix(
      when(hasError)(
        rounded(5),
      )(
        // this would be the `else` case
        rounded(10),
      ),
    );
    
    opened by bdlukaa 2
  • [Bug] Cannot use tokens space classes (not exported?)

    [Bug] Cannot use tokens space classes (not exported?)

    Accorded to the documentation I should be able to customize spaces with the MixThemeSpace. However it seems that the theme/tokens/space.dart are not being exported from mix package.

    library mix;
    
    export 'src/attributes/attribute.dart';
    export 'src/attributes/helpers/helper.utils.dart';
    export 'src/attributes/shared/shared.attributes.dart';
    export 'src/attributes/shared/shared.utils.dart';
    export 'src/helpers/color.utils.dart';
    export 'src/helpers/extensions.dart';
    export 'src/mixer/mix_context.dart';
    export 'src/mixer/mix_factory.dart';
    export 'src/mixer/mix_values.dart';
    export 'src/theme/material_theme/color_scheme_tokens.dart';
    export 'src/theme/material_theme/material_tokens.dart';
    export 'src/theme/material_theme/text_theme_tokens.dart';
    export 'src/theme/mix_theme.dart';
    export 'src/theme/refs/color_token.dart';
    export 'src/theme/refs/text_style_token.dart';
    export 'src/theme/tokens/size.dart';
    export 'src/utilities/box_decorator_utilities.dart';
    export 'src/utilities/box_utilities.dart';
    export 'src/utilities/dynamic_variants_utilities.dart';
    export 'src/utilities/flex_utilities.dart';
    export 'src/utilities/helper_utilities.dart';
    export 'src/utilities/icon_utilities.dart';
    export 'src/utilities/image_utilities.dart';
    export 'src/utilities/shared_utilities.dart';
    export 'src/utilities/text_utilities.dart';
    export 'src/utilities/zbox_utilities.dart';
    export 'src/variants/dynamic_variants/dynamic_variants.utils.dart';
    export 'src/variants/variant.dart';
    export 'src/widgets/box/box.attributes.dart';
    export 'src/widgets/box/box.utils.dart';
    export 'src/widgets/box/box.widget.dart';
    export 'src/widgets/box/box_decorators/aspect_ratio.dart';
    export 'src/widgets/box/box_decorators/clip_decorator.dart';
    export 'src/widgets/box/box_decorators/flexible.dart';
    export 'src/widgets/box/box_decorators/opacity.dart';
    export 'src/widgets/box/box_decorators/rotate.dart';
    export 'src/widgets/box/box_decorators/scale.dart';
    export 'src/widgets/flex/flex.attributes.dart';
    export 'src/widgets/flex/flex.utils.dart';
    export 'src/widgets/flex/flex.widget.dart';
    export 'src/widgets/gap.widget.dart';
    export 'src/widgets/icon/icon.attributes.dart';
    export 'src/widgets/icon/icon.utils.dart';
    export 'src/widgets/icon/icon.widget.dart';
    export 'src/widgets/image/image.attributes.dart';
    export 'src/widgets/image/image.utils.dart';
    export 'src/widgets/mix_context_builder.dart';
    export 'src/widgets/mixable.widget.dart';
    export 'src/widgets/pressable/gesture_box.widget.dart';
    export 'src/widgets/pressable/pressable.widget.dart';
    export 'src/widgets/pressable/pressable.widget.dart';
    export 'src/widgets/text/text.attributes.dart';
    export 'src/widgets/text/text.utils.dart';
    export 'src/widgets/text/text.widget.dart';
    export 'src/widgets/zbox/zbox.attributes.dart';
    export 'src/widgets/zbox/zbox.utils.dart';
    export 'src/widgets/zbox/zbox.widget.dart';
    
    opened by Maus3rSR 1
  • [Bug] press variant style apply time from Pressable widget seems to be longer than Material Buttons press effect

    [Bug] press variant style apply time from Pressable widget seems to be longer than Material Buttons press effect

    Hello,

    Thank you for this awesome library. Im still a beginner developer so sorry if I misunderstood something...

    I tried a sample app to use your pressable widget

    import 'dart:io';
    
    import 'package:flutter/material.dart';
    import 'package:mix/mix.dart';
    
    Mix get pressableMix => Mix(
          elevation(8),
          padding(20),
          rounded(30),
          bgColor(Colors.white),
          border(
            color: Colors.black,
            width: 2,
          ),
          hover(
            border(
              color: Colors.green,
            ),
          ),
          press(
            elevation(1),
            border(
              color: Colors.green,
              width: 4,
            ),
          ),
        );
    
    class BaseStyleButton extends StatelessWidget {
      const BaseStyleButton({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Pressable(
          onPressed: () {
            stdout.write("BaseStyleButton pressed");
          },
          child: Box(
            mix: pressableMix,
            child: const TextMix('Button'),
          ),
        );
      }
    }
    

    and implement it in a sample app, along to a TextButton

    import 'dart:io';
    
    import 'package:flutter/material.dart';
    import 'package:ultrashot_design_system/component.dart';
    
    void main() {
      runApp(const UltrashotApp());
    }
    
    class UltrashotApp extends StatelessWidget {
      const UltrashotApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Ultrashot ALPHA',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const DesignSystemShowCase(),
        );
      }
    }
    
    class DesignSystemShowCase extends StatelessWidget {
      const DesignSystemShowCase({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Ultrashot Design System'),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                const BaseStyleButton(),
                TextButton(
                  onPressed: () {
                    stdout.write("BaseStyleButton pressed");
                  },
                  child: const Text('Button'),
                )
              ],
            ),
          ),
        );
      }
    }
    

    On my ANDROID 9 / SAMSUNG S8 (SM-G950F)

    It seems that the press variant is applied on a longer press than the press effect of the material button. I can see the debug message by pressing the button without be able to see the press variant applied. However the material button press effect is instant when I press it with the same tap pression.

    bug 
    opened by Maus3rSR 7
  • [Proposal] Replace mix theming with material theme extensions

    [Proposal] Replace mix theming with material theme extensions

    We can take advantage of Material's theme extensions to replace the current mix theming. Currently, we define global variables and attach value to them in a MixThemeData, so that we can use globally.

    Proposal

    A callback based function theme<T extends ThemeExtension>((T)) that can be called inside a Mix. The mixer will look into every attribute for a theme and perform the operation based on the current context.

    Something like:

    final mix = Mix(
      bgColor(theme<MyColors>((myColors) => myColors.brandColor)),
      textColor(theme<MyColors>((myColors) => myColors.danger))),
    );
    
    // This is from the official example. Link attached below
    @immutable
    class MyColors extends ThemeExtension<MyColors> {
      const MyColors({
        required this.brandColor,
        required this.danger,
      });
    
      final Color? brandColor;
      final Color? danger;
    
      ...
    }
    

    Other things I have considered Making theme more readable and usable with something like

    final mix = Mix(
      bgColor(theme<MyColors>().brandColor),
      textColor(theme<MyColors>().danger),
    );
    

    But I can't seem to find a way where theme would have access to the current context

    Additional context https://api.flutter.dev/flutter/material/ThemeData/extensions.html

    opened by bdlukaa 3
  • Keyboard key press Dynamic Variant

    Keyboard key press Dynamic Variant

    This would be a variant that would react to a keyboard key press. It'd be something like:

    final mix = Mix(
      key(LogicalKeyboardKey.enter)(
        bgColor(Colors.red),
      ),
    );
    

    The key(<LogicalKeyboardKey>) would make the following possible:

    Mix(
      (hover & key(LogicalKeyboardKey.enter) & ...)(
      ),
    );
    

    Pressable could be used to handle this, or maybe a new widget could also be created

    See also:

    • https://api.flutter.dev/flutter/services/KeyDownEvent-class.html
    add-on 
    opened by bdlukaa 1
  • [Question] TextMix

    [Question] TextMix

    Reading the documentation

    TextMix(
      'Mix is AWESOME!'
      mix: Mix(
        fontSize(16.0),
        textColor(Colors.black),
        bold(),
        textShadow(
          offset: const Offset(2.0, 2.0),
        ),
      ),
    ),
    

    My understanding is that a mix passed as parameters will override any other inherited value but this is not reflected in my code. Not sure if it is a bug.

    Thx!

    opened by Solido 2
Owner
Leo Farias
Leo Farias
Windows95 UI components for Flutter apps. Bring back the nostalgic look and feel of old operating systems with this set of UI components ready to use.

Flutter95 Windows95 UI components for Flutter apps. UNDER CONSTRUCTION Screenshots Components Scaffold95 Scaffold as a Windows95 styled window. Provid

Miguel Beltran 141 Jan 2, 2023
Official Flutter SDK for Khalti Payment systems

Khalti Payment Gateway for Flutter Use Khalti Payment Gateway solution in your app or website to simplify payment for your customers. You do not need

Khalti 16 Oct 13, 2022
This is not an app. I made this architecture to build robust and easy-to-maintain products but in a faster way.

simple_architecture_flutter This is not an app. I made this architecture to build robust and easy-to-maintain products but in a faster way. Info I use

Batuhan Karababa 9 Oct 28, 2022
A Simple Todo app design in Flutter to keep track of your task on daily basis. Its build on BLoC Pattern. You can add a project, labels, and due-date to your task also you can sort your task on the basis of project, label, and dates

WhatTodo Life can feel overwhelming. But it doesn’t have to. A Simple To-do app design in flutter to keep track of your task on daily basis. You can a

Burhanuddin Rashid 1k Jan 6, 2023
Arisshopuiiesm - Build a clean and elegant Shop UI design for your Flutter app

Flutter Tutorial - 2/3 Shop UI - From Scratch We will build a clean and elegant

Behruz Hurramov 3 Oct 29, 2022
A Flutter application for Muslims that help them challenge and motivate themselves and their friends to read Azkar in a fun way.

A Flutter application for Muslims that help them challenge and motivate themselves and their friends to read Azkar in a fun way.

null 33 Oct 30, 2022
Create a simple way to keep track of weekly expenses with flutter

Expenses app The purpose of this app is to create a simple way to keep track of weekly expenses UI Getting Started This project is a starting point fo

Murilo Benassi 2 Jul 26, 2022
The FlexGrid control provides a powerful and quickly way to display data in a tabular format. It is including that frozened column/row,loading more, high performance and better experience in TabBarView/PageView.

flex_grid Language: English| 中文简体 The FlexGrid control provides a powerful and quickly way to display data in a tabular format. It is including that f

FlutterCandies 39 Nov 8, 2022
A news application that fetches the latest news via an API and displays, in a reverse sorted chronological way.

News App Description A news application that fetches the latest news via an API and displays, in a reverse sorted chronological way. Features Nativ Sp

Nishant Andoriya 3 Jun 24, 2022
An app that could help doctors better consult their patients in every way possible.

doc_app A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this

Kevin Jacob 1 Oct 15, 2021
cosmic_frontmatter is a package that provides a simple way to parse the frontmatter of a markdown file.

cosmic_frontmatter cosmic_frontmatter is a package that provides a simple way to parse the frontmatter of a markdown file. Getting started To get star

cosmic.horse 9 Oct 26, 2022
Helping navigate through maps to prefer road-way.

pothole-detector Detecting potholes using a smartphone app, & display the data to users over maps (google or open-street) through a app. In future, th

DEVSTRONS' 7 Dec 15, 2022
small package to generate code in a simple way

PART OF QUEEN PACKAGES ?? Dart File Builder Motivation generating dart code with build_runner will not work if you are trying to convert json to dart

FlutterQueen 3 Sep 24, 2022
Provide easy and flexible way to show SnackBar. Simple text, undo, and error style are supported.

snack_bar_presenter Provide easy and flexible way to show SnackBar. Simple text, undo, and error style are supported. . . . Usage import 'package:exam

Masayuki Ono (mono) 8 Nov 30, 2020
Easy way to store http response.

Starlight Http Cached The easiest way to store data such as http response,String,int,double,bool,map,list. Features ☑️ Set Cached ☑️ Get Cached ☑️ Del

Ye Myo Aung 3 Jan 9, 2023
The easiest way to show notification.

Starlight Notification The easiest way to show notification. Features ☑️ Show Notification ☑️ Cancel Notification ☑️ Cancel All Notification Watch the

Ye Myo Aung 1 Oct 19, 2022
This plugin lets you show a message in a simple way.

error_message This plugin lets you show a message in a simple way. Usage ErrorMessage( icon: Icon(Icons.error), title: "Error Title",

TamilKannan-Developer 0 Dec 5, 2021
Simple way to manage database.

database_manager (Developer Preview) Simple way to manage database. Version control and application's database schema. Simplify CRUD operations. Insta

Antonino Di Natale 4 Jul 14, 2021
An app for sharing polls in an interactive and anonymous way

Stay Home Polls App An app for sharing surveys in an interactive and anonymous way, mainly on sociocultural issues produced by the period of confineme

Albert Mañosa 6 Nov 21, 2022