Skip to content

Commit f8f162c

Browse files
authored
Adjust text-decoration-line cascading logic (#843)
Related to #842
1 parent e2f10e1 commit f8f162c

File tree

6 files changed

+57
-17
lines changed

6 files changed

+57
-17
lines changed

demo_app/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ packages:
216216
path: "../packages/core"
217217
relative: true
218218
source: path
219-
version: "0.9.0+1"
219+
version: "0.9.0+2"
220220
frontend_server_client:
221221
dependency: transitive
222222
description:

demo_app/test/goldens.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,6 @@
202202
"inline/text-align/start/rtl": "<div dir=\"rtl\"><div style=\"text-align: start\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut non elementum quam. Suspendisse odio diam, maximus pellentesque nunc a, pulvinar facilisis erat. Vivamus a viverra sem. Vivamus vehicula nibh mi, quis ornare orci laoreet vitae. Maecenas sagittis rutrum nisl nec dignissim. Suspendisse cursus est ut ultrices volutpat. Cras vel vestibulum arcu. Curabitur eget molestie nunc. Quisque fringilla quam vitae rhoncus lacinia. Vivamus id laoreet metus. Etiam sed mollis tellus. Vivamus facilisis faucibus libero eu interdum. Pellentesque laoreet magna porta viverra faucibus.</div></div>",
203203
"inline/text-decoration/color": "<span style=\"text-decoration: red underline\">foo</span>",
204204
"inline/text-decoration/line-through": "<span style=\"text-decoration: line-through\">line</span>",
205-
"inline/text-decoration/none": "<span style=\"text-decoration: line-through overline underline\">foo <span style=\"text-decoration: none\">bar</span></span>",
206205
"inline/text-decoration/overline": "<span style=\"text-decoration: overline\">over</span>",
207206
"inline/text-decoration/style/dotted": "<span style=\"text-decoration: underline dotted\">foo</span>",
208207
"inline/text-decoration/style/dashed": "<span style=\"text-decoration: underline dashed\">foo</span>",
-10.6 KB
Binary file not shown.

packages/core/lib/src/internal/ops/style_text_decoration.dart

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,25 +67,39 @@ TextStyleHtml textDecorationColor(TextStyleHtml p, Color v) =>
6767
p.copyWith(style: p.style.copyWith(decorationColor: v));
6868

6969
TextStyleHtml textDecorationLine(TextStyleHtml p, TextDecorationLine v) {
70-
final pd = p.style.decoration;
71-
final lineThough = pd?.contains(TextDecoration.lineThrough) == true;
72-
final overline = pd?.contains(TextDecoration.overline) == true;
73-
final underline = pd?.contains(TextDecoration.underline) == true;
70+
final parent = p.parent?.style.decoration;
71+
final parentOverline = parent?.contains(TextDecoration.overline) == true;
72+
final parentLineThrough =
73+
parent?.contains(TextDecoration.lineThrough) == true;
74+
final parentUnderline = parent?.contains(TextDecoration.underline) == true;
75+
76+
final current = p.style.decoration;
77+
final currentOverline = current?.contains(TextDecoration.overline) == true;
78+
final currentLineThrough =
79+
current?.contains(TextDecoration.lineThrough) == true;
80+
final currentUnderline = current?.contains(TextDecoration.underline) == true;
7481

7582
final list = <TextDecoration>[];
76-
if (v.over == true || (overline && v.over != false)) {
83+
if (parentOverline || (v.over ?? currentOverline)) {
84+
// 1. Honor parent's styling if the line decoration is turned on
85+
// 2. Then apply incoing value (if set)
86+
// 3. Finally fallback to the current styling
87+
//
88+
// According to https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration
89+
// > Text decorations are drawn across descendant text elements.
90+
// > This means that if an element specifies a text decoration,
91+
// > then a child element can't remove the decoration.
7792
list.add(TextDecoration.overline);
7893
}
79-
if (v.strike == true || (lineThough && v.strike != false)) {
94+
if (parentLineThrough || (v.strike ?? currentLineThrough)) {
8095
list.add(TextDecoration.lineThrough);
8196
}
82-
if (v.under == true || (underline && v.under != false)) {
97+
if (parentUnderline || (v.under ?? currentUnderline)) {
8398
list.add(TextDecoration.underline);
8499
}
85100

86-
return p.copyWith(
87-
style: p.style.copyWith(decoration: TextDecoration.combine(list)),
88-
);
101+
final combined = TextDecoration.combine(list);
102+
return p.copyWith(style: p.style.copyWith(decoration: combined));
89103
}
90104

91105
TextStyleHtml textDecorationStyle(TextStyleHtml p, TextDecorationStyle v) =>

packages/core/test/core_test.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ Future<void> main() async {
4141
<span style="text-decoration: overline">
4242
<span style="text-decoration: underline">
4343
All decorations...
44-
<span style="text-decoration: none">and none</span>
4544
</span>
4645
</span>
4746
</span>
@@ -56,8 +55,7 @@ Future<void> main() async {
5655
str,
5756
equals(
5857
'[Column:children='
59-
'[CssBlock:child=[RichText:(:(+l+o+u:All decorations... )'
60-
'(:and none))]],'
58+
'[CssBlock:child=[RichText:(+l+o+u:All decorations...)]],'
6159
'[CssBlock:child=[RichText:(:I​Like​Playing​football​​game)]],'
6260
'[CssBlock:child=[RichText:(:\u00A0)]]'
6361
']',

packages/core/test/style_text_decoration_test.dart

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,41 @@ foo</span></span></span>
141141
expect(explained, equals('[RichText:(+l+o+u:foo)]'));
142142
});
143143

144-
testWidgets('renders none', (WidgetTester tester) async {
144+
testWidgets('renders all (child with none)', (WidgetTester tester) async {
145145
const html =
146146
'<span style="text-decoration: line-through overline underline">foo '
147147
'<span style="text-decoration-line: none">bar</span></span>';
148148
final explained = await explain(tester, html);
149-
expect(explained, equals('[RichText:(:(+l+o+u:foo )(:bar))]'));
149+
expect(explained, equals('[RichText:(:(+l+o+u:foo )(+l+o+u:bar))]'));
150+
});
151+
152+
testWidgets('renders none after line-through', (WidgetTester tester) async {
153+
const html = '<span style="text-decoration-line: line-through; '
154+
'text-decoration-line: none">foo</span>';
155+
final explained = await explain(tester, html);
156+
expect(explained, equals('[RichText:(:foo)]'));
157+
});
158+
159+
testWidgets('renders none after overline', (WidgetTester tester) async {
160+
const html = '<span style="text-decoration-line: overline; '
161+
'text-decoration-line: none">foo</span>';
162+
final explained = await explain(tester, html);
163+
expect(explained, equals('[RichText:(:foo)]'));
164+
});
165+
166+
testWidgets('renders none after underline', (WidgetTester tester) async {
167+
const html = '<span style="text-decoration-line: underline; '
168+
'text-decoration-line: none">foo</span>';
169+
final explained = await explain(tester, html);
170+
expect(explained, equals('[RichText:(:foo)]'));
171+
});
172+
173+
testWidgets('renders none after all', (WidgetTester tester) async {
174+
const html =
175+
'<span style="text-decoration-line: line-through overline underline; '
176+
'text-decoration-line: none">foo</span>';
177+
final explained = await explain(tester, html);
178+
expect(explained, equals('[RichText:(:foo)]'));
150179
});
151180
});
152181

0 commit comments

Comments
 (0)