[flutter_markdown] Fix shrinkWrap not taken into account with single child (#2195)
diff --git a/packages/flutter_markdown/CHANGELOG.md b/packages/flutter_markdown/CHANGELOG.md
index 1b31a06..091ab1e 100644
--- a/packages/flutter_markdown/CHANGELOG.md
+++ b/packages/flutter_markdown/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.6.10+3
+
+* Fixes shrinkWrap not taken into account with single child ([flutter/flutter#105299](https://github.com/flutter/flutter/issues/105299)).
+
## 0.6.10+2
* Migrates from `ui.hash*` to `Object.hash*`.
diff --git a/packages/flutter_markdown/example/lib/demos/markdown_body_shrink_wrap_demo.dart b/packages/flutter_markdown/example/lib/demos/markdown_body_shrink_wrap_demo.dart
new file mode 100644
index 0000000..97c3daa
--- /dev/null
+++ b/packages/flutter_markdown/example/lib/demos/markdown_body_shrink_wrap_demo.dart
@@ -0,0 +1,104 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_markdown/flutter_markdown.dart';
+import '../shared/dropdown_menu.dart';
+import '../shared/markdown_demo_widget.dart';
+
+// ignore_for_file: public_member_api_docs
+
+const String _data = '''
+**MarkdownBody**
+''';
+
+const String _notes = '''
+# Shrink wrap demo
+---
+
+## Overview
+
+This example demonstrates how `MarkdownBody`'s `shrinkWrap` property works.
+
+- If `shrinkWrap` is `true`, `MarkdownBody` will take the minimum height that
+ wraps its content.
+- If `shrinkWrap` is `false`, `MarkdownBody` will expand to the maximum allowed
+ height.
+''';
+
+class MarkdownBodyShrinkWrapDemo extends StatefulWidget
+ implements MarkdownDemoWidget {
+ const MarkdownBodyShrinkWrapDemo({Key? key}) : super(key: key);
+
+ static const String _title = 'Shrink wrap demo';
+
+ @override
+ String get title => MarkdownBodyShrinkWrapDemo._title;
+
+ @override
+ String get description => "This example demonstrates how MarkdownBody's "
+ 'shrinkWrap property works.';
+
+ @override
+ Future<String> get data => Future<String>.value(_data);
+
+ @override
+ Future<String> get notes => Future<String>.value(_notes);
+
+ @override
+ State<MarkdownBodyShrinkWrapDemo> createState() =>
+ _MarkdownBodyShrinkWrapDemoState();
+}
+
+class _MarkdownBodyShrinkWrapDemoState
+ extends State<MarkdownBodyShrinkWrapDemo> {
+ bool _shrinkWrap = true;
+
+ final Map<String, bool> _shrinkWrapMenuItems = <String, bool>{
+ 'true': true,
+ 'false': false,
+ };
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: <Widget>[
+ DropdownMenu<bool>(
+ items: _shrinkWrapMenuItems,
+ label: 'Shrink wrap:',
+ initialValue: _shrinkWrap,
+ onChanged: (bool? value) {
+ if (value != _shrinkWrap) {
+ setState(() {
+ _shrinkWrap = value!;
+ });
+ }
+ },
+ ),
+ Expanded(
+ child: Stack(
+ children: <Widget>[
+ Align(
+ alignment: Alignment.bottomCenter,
+ child: Container(
+ decoration: BoxDecoration(
+ color: Colors.grey.withOpacity(0.5),
+ border: Border.all(
+ color: Colors.red,
+ width: 2,
+ ),
+ ),
+ child: MarkdownBody(
+ data: _data,
+ shrinkWrap: _shrinkWrap,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/packages/flutter_markdown/example/lib/screens/home_screen.dart b/packages/flutter_markdown/example/lib/screens/home_screen.dart
index 5d32544..df17ab0 100644
--- a/packages/flutter_markdown/example/lib/screens/home_screen.dart
+++ b/packages/flutter_markdown/example/lib/screens/home_screen.dart
@@ -6,6 +6,7 @@
import '../demos/basic_markdown_demo.dart';
import '../demos/centered_header_demo.dart';
import '../demos/extended_emoji_demo.dart';
+import '../demos/markdown_body_shrink_wrap_demo.dart';
import '../demos/minimal_markdown_demo.dart';
import '../demos/original_demo.dart';
import '../demos/subscript_syntax_demo.dart';
@@ -28,6 +29,7 @@
const ExtendedEmojiDemo(),
OriginalMarkdownDemo(),
const CenteredHeaderDemo(),
+ const MarkdownBodyShrinkWrapDemo(),
];
@override
diff --git a/packages/flutter_markdown/lib/src/builder.dart b/packages/flutter_markdown/lib/src/builder.dart
index 0f6b20e..fe7ab32 100644
--- a/packages/flutter_markdown/lib/src/builder.dart
+++ b/packages/flutter_markdown/lib/src/builder.dart
@@ -364,6 +364,7 @@
if (current.children.isNotEmpty) {
child = Column(
+ mainAxisSize: MainAxisSize.min,
crossAxisAlignment: fitContent
? CrossAxisAlignment.start
: CrossAxisAlignment.stretch,
diff --git a/packages/flutter_markdown/lib/src/widget.dart b/packages/flutter_markdown/lib/src/widget.dart
index 0e4ca00..6a0c28a 100644
--- a/packages/flutter_markdown/lib/src/widget.dart
+++ b/packages/flutter_markdown/lib/src/widget.dart
@@ -436,12 +436,14 @@
softLineBreak: softLineBreak,
);
- /// See [ScrollView.shrinkWrap]
+ /// If [shrinkWrap] is `true`, [MarkdownBody] will take the minimum height
+ /// that wraps its content. Otherwise, [MarkdownBody] will expand to the
+ /// maximum allowed height.
final bool shrinkWrap;
@override
Widget build(BuildContext context, List<Widget>? children) {
- if (children!.length == 1) {
+ if (children!.length == 1 && shrinkWrap) {
return children.single;
}
return Column(
diff --git a/packages/flutter_markdown/pubspec.yaml b/packages/flutter_markdown/pubspec.yaml
index 1e8634c..716fca4 100644
--- a/packages/flutter_markdown/pubspec.yaml
+++ b/packages/flutter_markdown/pubspec.yaml
@@ -4,7 +4,7 @@
formatted with simple Markdown tags.
repository: https://github.com/flutter/packages/tree/main/packages/flutter_markdown
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_markdown%22
-version: 0.6.10+2
+version: 0.6.10+3
environment:
sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/flutter_markdown/test/markdown_body_shrink_wrap_test.dart b/packages/flutter_markdown/test/markdown_body_shrink_wrap_test.dart
new file mode 100644
index 0000000..4cf2afc
--- /dev/null
+++ b/packages/flutter_markdown/test/markdown_body_shrink_wrap_test.dart
@@ -0,0 +1,73 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/widgets.dart';
+import 'package:flutter_markdown/flutter_markdown.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'utils.dart';
+
+void main() => defineTests();
+
+void defineTests() {
+ group('MarkdownBody shrinkWrap test', () {
+ testWidgets(
+ 'Given a MarkdownBody with shrinkWrap=true '
+ 'Then it wraps its content',
+ (WidgetTester tester) async {
+ await tester.pumpWidget(boilerplate(Stack(
+ children: const <Widget>[
+ Text('shrinkWrap=true'),
+ Align(
+ alignment: Alignment.bottomCenter,
+ child: MarkdownBody(
+ data: 'This is a [link](https://flutter.dev/)',
+ shrinkWrap: true,
+ ),
+ ),
+ ],
+ )));
+
+ final Rect stackRect = tester.getRect(find.byType(Stack));
+ final Rect textRect = tester.getRect(find.byType(Text));
+ final Rect markdownBodyRect = tester.getRect(find.byType(MarkdownBody));
+
+ // The Text should be on the top of the Stack
+ expect(textRect.top, equals(stackRect.top));
+ expect(textRect.bottom, lessThan(stackRect.bottom));
+ // The MarkdownBody should be on the bottom of the Stack
+ expect(markdownBodyRect.top, greaterThan(stackRect.top));
+ expect(markdownBodyRect.bottom, equals(stackRect.bottom));
+ },
+ );
+ testWidgets(
+ 'Given a MarkdownBody with shrinkWrap=false '
+ 'Then it expands to the maximum allowed height',
+ (WidgetTester tester) async {
+ await tester.pumpWidget(boilerplate(Stack(
+ children: const <Widget>[
+ Text('shrinkWrap=false test'),
+ Align(
+ alignment: Alignment.bottomCenter,
+ child: MarkdownBody(
+ data: 'This is a [link](https://flutter.dev/)',
+ shrinkWrap: false,
+ ),
+ ),
+ ],
+ )));
+
+ final Rect stackRect = tester.getRect(find.byType(Stack));
+ final Rect textRect = tester.getRect(find.byType(Text));
+ final Rect markdownBodyRect = tester.getRect(find.byType(MarkdownBody));
+
+ // The Text should be on the top of the Stack
+ expect(textRect.top, equals(stackRect.top));
+ expect(textRect.bottom, lessThan(stackRect.bottom));
+ // The MarkdownBody should take all Stack's height
+ expect(markdownBodyRect.top, equals(stackRect.top));
+ expect(markdownBodyRect.bottom, equals(stackRect.bottom));
+ },
+ );
+ });
+}