Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] InheritedAttribute - Extend Mix functionality with custom attributes. #94

Merged
merged 9 commits into from
Sep 27, 2022
Merged
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
2 changes: 2 additions & 0 deletions lib/mix.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ export 'src/theme/mix_theme.dart';
export 'src/theme/refs/color_token.dart';
export 'src/theme/refs/text_style_token.dart';
export 'src/variants/variants.dart';


21 changes: 21 additions & 0 deletions lib/src/attributes/common/attribute.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@ abstract class Attribute {
const Attribute();
}

/// An interface that add support to custom attributes for [MixContext].
abstract class InheritedAttribute<T extends InheritedAttribute<T>>
extends Attribute {
const InheritedAttribute();

InheritedAttribute<T> merge(covariant InheritedAttribute<T>? other);

Object get type => T;
}

class InheritedAttributes {
final Map<Object, InheritedAttribute<dynamic>> attributes;

InheritedAttributes(this.attributes);

/// Used to obtain a [InheritedAttribute] from [MixContext].
///
/// Obtain with `mixContext.fromType<MyAttributeExtension>()`.
T? fromType<T>() => attributes[T] as T?;
}

/// Allows to pass down Mixes as attributes for use with helpers
class NestedAttribute<T extends Attribute> extends Attribute {
const NestedAttribute(this.attributes);
Expand Down
41 changes: 41 additions & 0 deletions lib/src/mixer/mix_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ extension DecoratorMapExtension on DecoratorMap {

class MixContext {
final BuildContext context;
final InheritedAttributes inheritedAttributes;
final Mix sourceMix;
final Mix originalMix;

Expand All @@ -42,6 +43,16 @@ class MixContext {
final FlexProps flexProps;
final ZBoxProps zBoxProps;

/// Used to obtain a [InheritedAttribute] from [InheritedAttributes].
///
/// Obtain with `mixContext.fromType<MyInheritedAttribute>()`.
T fromType<T extends InheritedAttribute<T>>() {
final attribute = inheritedAttributes.fromType<T>();
debugCheckInheritedAttribute<T>(attribute);

return attribute!;
}

MixContext._({
required this.context,
required this.sourceMix,
Expand All @@ -55,6 +66,7 @@ class MixContext {
required this.directives,
required this.variants,
required this.decorators,
required this.inheritedAttributes,
});

factory MixContext.create({
Expand Down Expand Up @@ -93,6 +105,7 @@ class MixContext {
required Mix<T> mix,
}) {
final _attributes = _expandAttributes(context, mix);

BoxAttributes? boxAttributes;
IconAttributes? iconAttributes;
FlexAttributes? flexAttributes;
Expand All @@ -105,7 +118,21 @@ class MixContext {
final variants = <VariantAttribute>[];
final decorators = <Decorator>[];

final Map<Object, InheritedAttribute> inheritedAttributesMap = {};

for (final attribute in _attributes) {
if (attribute is InheritedAttribute) {
var inheritedAttribute = inheritedAttributesMap[attribute.type];

if (inheritedAttribute == null) {
inheritedAttribute = attribute;
} else {
inheritedAttribute = inheritedAttribute.merge(attribute);
}

inheritedAttributesMap[attribute.type] = inheritedAttribute;
}

if (attribute is VariantAttribute) {
variants.add(attribute);
}
Expand Down Expand Up @@ -211,6 +238,7 @@ class MixContext {
directives: directives,
variants: variants,
decorators: decoratorMap,
inheritedAttributes: InheritedAttributes(inheritedAttributesMap),
);
}

Expand Down Expand Up @@ -335,3 +363,16 @@ class MixContext {
// );
// }
}

/// Asserts that the given mixContext has a [T] attribute.
void debugCheckInheritedAttribute<T extends InheritedAttribute<T>>(
InheritedAttribute? attribute,
) {
assert(() {
return attribute is T;
}(), '''
No $T could be found starting from the mixContext
when call mixContext.fromType<$T>(). This can happen because you
have not create a Mix with $T.
''');
}
1 change: 1 addition & 0 deletions lib/src/mixer/mix_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class Mix<T extends Attribute> {
}

/// Merges many mixes into one
// ignore: long-parameter-list
static Mix<T> combine<T extends Attribute>([
Mix<T>? mix1,
Mix<T>? mix2,
Expand Down
1 change: 1 addition & 0 deletions lib/src/widgets/box.widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,4 @@ class BoxMixedWidget extends MixedWidget {
return current;
}
}

6 changes: 5 additions & 1 deletion lib/src/widgets/mix_context_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import 'package:mix/src/variants/variants.dart';
import 'package:mix/src/widgets/mixable.widget.dart';

typedef WidgetMixBuilder<T> = Widget Function(
BuildContext context, MixContext mixContext);
BuildContext context,
MixContext mixContext,
);

class MixContextBuilder extends MixableWidget {
const MixContextBuilder({
Expand All @@ -27,6 +29,7 @@ class MixContextBuilder extends MixableWidget {
@override
Widget build(BuildContext context) {
final mixContext = getMixContext(context);

return MixContextNotifier(
mixContext,
child: builder(
Expand All @@ -36,3 +39,4 @@ class MixContextBuilder extends MixableWidget {
);
}
}

7 changes: 5 additions & 2 deletions lib/src/widgets/mixable.widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,11 @@ abstract class MixableWidget extends StatelessWidget {
DiagnosticsProperty<Mix>('mix', _mix, defaultValue: null),
);
properties.add(
DiagnosticsProperty<List<Variant>>('variants', _variants,
defaultValue: null),
DiagnosticsProperty<List<Variant>>(
'variants',
_variants,
defaultValue: null,
),
);
properties.add(
DiagnosticsProperty<bool>('inherit', _inherit, defaultValue: true),
Expand Down
Loading