Skip to content

Commit

Permalink
Add isInheritable property
Browse files Browse the repository at this point in the history
remove RenderWidgetDecorators when there isnt decorators attributes in style
  • Loading branch information
tilucasoli committed Jan 20, 2024
1 parent 1877696 commit 1cd3910
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 24 deletions.
3 changes: 3 additions & 0 deletions lib/src/core/attribute.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ abstract class Attribute with Comparable {

// Used as a merge type
Object get type;

// Used to determine if the attribute is inheritable
bool get isInheritable => true;
}

@immutable
Expand Down
3 changes: 3 additions & 0 deletions lib/src/core/decorator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ abstract class Decorator<Self extends Decorator<Self>> extends StyleAttribute {
@override
Object get type => Self;

@override
bool get isInheritable => false;

Widget build(MixData mix, Widget child);
}

Expand Down
10 changes: 1 addition & 9 deletions lib/src/core/styled_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import 'package:flutter/material.dart';
import '../factory/mix_provider.dart';
import '../factory/mix_provider_data.dart';
import '../factory/style_mix.dart';
import 'attribute.dart';
import 'decorator.dart';

/// An abstract widget for applying custom styles.
///
Expand Down Expand Up @@ -39,11 +37,7 @@ abstract class StyledWidget extends StatelessWidget {
/// This method is typically used in the `build` method of widgets extending
/// [StyledWidget] to provide the actual styled widget.
Widget withMix(BuildContext context, MixBuilder builder) {
MixData? inheritedMix = inherit ? MixProvider.maybeOf(context) : null;

if (inheritedMix != null) {
inheritedMix = MixData.where(inheritedMix, _handleDecoratorsOnInhirit);
}
MixData? inheritedMix = inherit ? MixData.inherited(context) : null;

final mixData = MixData.create(context, style);

Expand All @@ -52,8 +46,6 @@ abstract class StyledWidget extends StatelessWidget {
return MixProvider(data: mergedMixData, child: builder(mergedMixData));
}

bool _handleDecoratorsOnInhirit(Attribute attr) => attr is! WidgetDecorator;

@override
Widget build(BuildContext context);
}
Expand Down
23 changes: 23 additions & 0 deletions lib/src/factory/mix_provider_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import '../core/attributes_map.dart';
import '../helpers/compare_mixin.dart';
import '../theme/mix_theme.dart';
import '../widgets/pressable/widget_state_util.dart';
import 'mix_provider.dart';
import 'style_mix.dart';

/// This class is used for encapsulating all [MixData] related operations.
Expand Down Expand Up @@ -50,6 +51,24 @@ class MixData with Comparable {
);
}

factory MixData.inherited(BuildContext context) {
final inheritedMix = MixProvider.maybeOf(context);

if (inheritedMix == null) {
return MixData.create(context, const Style.empty());
}

// Remove non-inheritable attributes
final inheritableAttributes = inheritedMix.where(
(attr) => attr.isInheritable,
);

return MixData._(
resolver: MixTokenResolver(context),
attributes: AttributeMap(inheritableAttributes),
);
}

/// Getter for [MixTokenResolver].
///
/// Returns [_tokenResolver].
Expand All @@ -73,6 +92,10 @@ class MixData with Comparable {
return _attributes.whereType<A>();
}

bool contains<T>() {
return _attributes.values.any((attr) => attr is T);
}

Iterable<Attribute> where(bool Function(Attribute attr) clousure) =>
attributes.values.where(clousure);

Expand Down
4 changes: 2 additions & 2 deletions lib/src/specs/container/box_widget.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import 'package:flutter/material.dart';

import '../../core/styled_widget.dart';
import '../../decorators/widget_decorator_widget.dart';
import '../../deprecations.dart';
import '../../factory/mix_provider.dart';
import '../../factory/mix_provider_data.dart';
import '../../utils/helper_util.dart';
import 'box_attribute.dart';
import 'box_spec.dart';

Expand Down Expand Up @@ -115,7 +115,7 @@ class MixedBox extends StatelessWidget {
final spec = BoxSpec.of(mix);

// Apply styles and decorators to the Container, which wraps the child widget.
return RenderWidgetDecorators(
return shouldApplyDecorators(
mix: mix,
orderOfDecorators: decoratorOrder,
child: Container(
Expand Down
10 changes: 3 additions & 7 deletions lib/src/specs/icon/icon_widget.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import 'package:flutter/material.dart';

import '../../core/styled_widget.dart';
import '../../decorators/widget_decorator_widget.dart';
import '../../factory/mix_provider.dart';
import '../../factory/mix_provider_data.dart';
import 'icon_attribute.dart';
import 'icon_spec.dart';
import '../../../mix.dart';

class StyledIcon extends StyledWidget {
const StyledIcon(
Expand Down Expand Up @@ -54,8 +49,9 @@ class MixedIcon extends StatelessWidget {
final mix = this.mix ?? MixProvider.of(context);
final spec = IconSpec.of(mix);

return RenderWidgetDecorators(
return shouldApplyDecorators(
mix: mix,
orderOfDecorators: decoratorOrder,
child: IconSpecWidget(
spec: spec,
semanticLabel: semanticLabel,
Expand Down
20 changes: 20 additions & 0 deletions lib/src/utils/helper_util.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import 'package:flutter/widgets.dart';

import '../core/decorator.dart';
import '../decorators/widget_decorator_widget.dart';
import '../factory/mix_provider_data.dart';

typedef FunctionWithParams<ParamT, ReturnT> = ReturnT Function(
List<ParamT> params,
);
Expand Down Expand Up @@ -35,3 +41,17 @@ class SpreadFunctionParams<ParamT, ReturnT> {
].whereType<ParamT>().toList());
}
}

Widget shouldApplyDecorators({
required MixData mix,
required Widget child,
List<Type> orderOfDecorators = const [],
}) {
return mix.contains<WidgetDecorator>()
? RenderWidgetDecorators(
mix: mix,
orderOfDecorators: orderOfDecorators,
child: child,
)
: child;
}
27 changes: 26 additions & 1 deletion test/src/decorators/widget_decorator_widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ void main() {
testWidgets('Renders decorators in the correct order', (tester) async {
await tester.pumpMaterialApp(
RenderWidgetDecorators(
mix: MixData.create(MockBuildContext(), style),
mix: mixData,
orderOfDecorators: const [
ClipDecorator,
AspectRatioDecorator,
Expand Down Expand Up @@ -287,5 +287,30 @@ void main() {
),
findsNothing);
});

testWidgets(
'If there are no decorator attributes in Style, RenderWidgetDecorators shouldnt exist in the widget tree',
(tester) async {
const key = Key('box');

await tester.pumpWidget(
Box(
key: key,
style: Style(
backgroundColor.red(),
height(100),
width(100),
),
),
);

expect(
find.descendant(
of: find.byKey(key),
matching: find.byType(RenderWidgetDecorators),
),
findsNothing,
);
});
});
}
38 changes: 33 additions & 5 deletions test/src/factory/mix_provider_data_test.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mix/src/core/attributes_map.dart';
import 'package:mix/src/factory/mix_provider_data.dart';
import 'package:mix/src/factory/style_mix.dart';
import 'package:mix/src/theme/mix_theme.dart';
import 'package:mix/src/variants/variant.dart';
import 'package:mix/mix.dart';

import '../../helpers/testing_utils.dart';

Expand Down Expand Up @@ -86,4 +83,35 @@ void main() {
expect(mergedMixData.attributeOf<MockDoubleScalarAttribute>(),
const MockDoubleScalarAttribute(4.0));
});

testWidgets('MixData.inherited shouldnt have attributes non inheritable',
(WidgetTester tester) async {
await tester.pumpWidget(
MixProvider(
data: MixData.create(
MockBuildContext(),
Style(
const _NonInheritableAttribute(),
icon.color.black(),
),
),
child: Builder(builder: (context) {
final inheritedMix = MixData.inherited(context);
final iconSpec = IconSpec.of(inheritedMix);

expect(inheritedMix.attributes.length, 1);
expect(iconSpec.color, Colors.black);
return const SizedBox();
}),
),
);
});
}

class _NonInheritableAttribute
extends ScalarAttribute<MockIntScalarAttribute, int?> {
const _NonInheritableAttribute() : super(null);

@override
bool get isInheritable => false;
}

0 comments on commit 1cd3910

Please sign in to comment.