Sub6Resources / flutter_html

A Flutter widget for rendering static html as Flutter widgets (Will render over 80 different html tags!)
https://pub.dev/packages/flutter_html
MIT License
1.79k stars 860 forks source link

[BUG] Top margin gets set to '[text]' margin #1155

Closed arjanmels closed 1 year ago

arjanmels commented 1 year ago

Describe the bug: The '[text]' elements get a bottom of margin of 32 in my case. In the _collapseMargins routine this gets collapsed into the next elements margin.

My solution/workaround add a Style to the style map with key '[text]' setting sthe margins to 0.

HTML to reproduce the issue:

<p>test1</p>
<p>test2</p>

Html widget configuration:

Html.fromDom(
            document: _document,
            style: buildContext.styles.htmlStyle,
            customRenders: {
              tableMatcher(): tableRender(),
              _summaryMatcher(): CustomRender.inlineSpan(inlineSpan: (context, buildChildren) {
                var style = context.tree.children.first.style;
                style.color = null;
                var textStyle = style.generateTextStyle();
                return WidgetSpan(child: Text(context.tree.element?.text ?? '', style: textStyle));
              }),
            },
          ),

Expected behavior: No margin on [text] element by default

Screenshots: N/A

Device details and Flutter/Dart/flutter_html versions: Version: 3.0.0-alpha6

Stacktrace/Logcat N/A Additional info: N/A

Sub6Resources commented 1 year ago

This is certainly odd. Can you give us an example of HTML that can reproduce this issue?

arjanmels commented 1 year ago

Structure of the html is:

<html lang="en">
<body>
<details>
    <summary><h1>Header 1</h1></summary>
    <details>
        <summary><h2>Hoe slapen werkt</h2></summary>
        <h3>Header 3</h3>
        <p>Paragraph 1</p>
        <h4>Header 4</h4>
        <p>Paragraph 2</p>
        <p>Paragraph 3</p>
    </details>
</details>
</body>
</html>

I can image that the style setup is also important. Unfortunately not entirely straightforward how I create it:

In this setup I already included my workaround with the '[text]' style

Style _createHTMLStyle(final TextStyle? textStyle,
      {FontWeight? fontWeight, double top = 0.5, double bottom = 0.25, double horizontal = 17}) {
    if (textStyle == null) {
      return Style(
          margin: Margins(
              top: Margin(top, Unit.rem),
              bottom: Margin(bottom, Unit.rem),
              left: Margin(horizontal, Unit.px),
              right: Margin(horizontal, Unit.px)));
    } else {
      return Style.fromTextStyle(textStyle).copyWith(fontWeight: fontWeight).copyWith(
          margin: Margins(
              top: Margin(top, Unit.rem),
              bottom: Margin(bottom, Unit.rem),
              left: Margin(horizontal, Unit.px),
              right: Margin(horizontal, Unit.px)));
    }
  }

  Map<String, Style> get htmlStyle {
    var textTheme = _context.theme.textTheme;
    return {
      'body': Style(margin: Margins.zero),
      'h1': _createHTMLStyle(textTheme.headlineMedium),
      'h2': _createHTMLStyle(textTheme.headlineSmall),
      'h3': _createHTMLStyle(textTheme.titleSmall, fontWeight: FontWeight.bold),
      'h4': _createHTMLStyle(textTheme.bodyMedium, fontWeight: FontWeight.bold),
      'h5': _createHTMLStyle(textTheme.bodyMedium),
      'h6': _createHTMLStyle(textTheme.bodyMedium),
      'p': _createHTMLStyle(textTheme.bodyMedium, top: 0, bottom: 1),
      'ul, ol': _createHTMLStyle(null, top: 0, bottom: 1),
      'table': _createHTMLStyle(null, top: 0, bottom: 1, horizontal: 17 / 2)
          .copyWith(padding: EdgeInsets.only(bottom: _scale * textTheme.bodyMedium!.fontSize! / 4)),
      'tr': Style(margin: Margins.only(right: -6)),
      'th': Style(fontWeight: FontWeight.bold),
      'td': Style(padding: const EdgeInsets.only(right: 3, bottom: 1.5), alignment: Alignment.topLeft),
      'details': Style(),
      'summary': Style(),
      '[text]': Style(margin: Margins.zero)
    };
  }
Sub6Resources commented 1 year ago

Thanks, This will take me a bit to work through but I'll take a look.

arjanmels commented 1 year ago

My workaround fails when there is no empty text element between tags. E.g. This html

<!DOCTYPE html>
<html>
<body>
    <div>
        <p>a</p><p>b</p>
        <p>d</p>
        <p>a</p><p>b</p>
    </div>
</body>
</html>

leads to this output:

a

b
d
a

b
arjanmels commented 1 year ago

I think I have found the problem. Margin was added both to bottom of previous block and top of next block. Pull Request #1237 should address it.

Sub6Resources commented 1 year ago

@arjanmels Thanks for catching that!