Skip to content

Commit 9d2888b

Browse files
authored
Merge pull request Sub6Resources#901 from tneotia/feature/text-transform
Support text transform CSS (Sub6Resources#894)
2 parents f50768a + 099f781 commit 9d2888b

File tree

4 files changed

+60
-2
lines changed

4 files changed

+60
-2
lines changed

lib/html_parser.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ class HtmlParser extends StatelessWidget {
446446
);
447447
} else if (tree is ReplacedElement) {
448448
if (tree is TextContentElement) {
449-
return TextSpan(text: tree.text);
449+
return TextSpan(text: tree.text?.transformed(tree.style.textTransform));
450450
} else {
451451
return WidgetSpan(
452452
alignment: tree.alignment,

lib/src/css_parser.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ Style declarationsToStyle(Map<String, List<css.Expression>> declarations) {
230230
break;
231231
}
232232
}
233+
break;
233234
case 'height':
234235
style.height = ExpressionMapping.expressionToPaddingLength(value.first) ?? style.height;
235236
break;
@@ -337,6 +338,18 @@ Style declarationsToStyle(Map<String, List<css.Expression>> declarations) {
337338
case 'text-shadow':
338339
style.textShadow = ExpressionMapping.expressionToTextShadow(value);
339340
break;
341+
case 'text-transform':
342+
final val = (value.first as css.LiteralTerm).text;
343+
if (val == 'uppercase') {
344+
style.textTransform = TextTransform.uppercase;
345+
} else if (val == 'lowercase') {
346+
style.textTransform = TextTransform.lowercase;
347+
} else if (val == 'capitalize') {
348+
style.textTransform = TextTransform.capitalize;
349+
} else {
350+
style.textTransform = TextTransform.none;
351+
}
352+
break;
340353
case 'width':
341354
style.width = ExpressionMapping.expressionToPaddingLength(value.first) ?? style.width;
342355
break;

lib/src/utils.dart

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import 'dart:convert';
22
import 'dart:math';
33

4-
import 'package:flutter/gestures.dart';
54
import 'package:flutter/material.dart';
5+
import 'package:flutter_html/style.dart';
66

77
Map<String, String> namedColors = {
88
"White": "#FFFFFF",
@@ -81,4 +81,34 @@ String getRandString(int len) {
8181
var random = Random.secure();
8282
var values = List<int>.generate(len, (i) => random.nextInt(255));
8383
return base64UrlEncode(values);
84+
}
85+
86+
extension TextTransformUtil on String? {
87+
String? transformed(TextTransform? transform) {
88+
if (this == null) return null;
89+
if (transform == TextTransform.uppercase) {
90+
return this!.toUpperCase();
91+
} else if (transform == TextTransform.lowercase) {
92+
return this!.toLowerCase();
93+
} else if (transform == TextTransform.capitalize) {
94+
final stringBuffer = StringBuffer();
95+
96+
var capitalizeNext = true;
97+
for (final letter in this!.toLowerCase().codeUnits) {
98+
// UTF-16: A-Z => 65-90, a-z => 97-122.
99+
if (capitalizeNext && letter >= 97 && letter <= 122) {
100+
stringBuffer.writeCharCode(letter - 32);
101+
capitalizeNext = false;
102+
} else {
103+
// UTF-16: 32 == space, 46 == period
104+
if (letter == 32 || letter == 46) capitalizeNext = true;
105+
stringBuffer.writeCharCode(letter);
106+
}
107+
}
108+
109+
return stringBuffer.toString();
110+
} else {
111+
return this;
112+
}
113+
}
84114
}

lib/style.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ class Style {
191191
///
192192
TextOverflow? textOverflow;
193193

194+
TextTransform? textTransform;
195+
194196
Style({
195197
this.backgroundColor = Colors.transparent,
196198
this.color,
@@ -225,6 +227,7 @@ class Style {
225227
this.markerContent,
226228
this.maxLines,
227229
this.textOverflow,
230+
this.textTransform = TextTransform.none,
228231
}) {
229232
if (this.alignment == null &&
230233
(display == Display.BLOCK || display == Display.LIST_ITEM)) {
@@ -317,6 +320,7 @@ class Style {
317320
markerContent: other.markerContent,
318321
maxLines: other.maxLines,
319322
textOverflow: other.textOverflow,
323+
textTransform: other.textTransform,
320324
);
321325
}
322326

@@ -354,6 +358,7 @@ class Style {
354358
wordSpacing: child.wordSpacing ?? wordSpacing,
355359
maxLines: child.maxLines ?? maxLines,
356360
textOverflow: child.textOverflow ?? textOverflow,
361+
textTransform: child.textTransform ?? textTransform,
357362
);
358363
}
359364

@@ -391,6 +396,7 @@ class Style {
391396
Widget? markerContent,
392397
int? maxLines,
393398
TextOverflow? textOverflow,
399+
TextTransform? textTransform,
394400
bool? beforeAfterNull,
395401
}) {
396402
return Style(
@@ -428,6 +434,7 @@ class Style {
428434
markerContent: markerContent ?? this.markerContent,
429435
maxLines: maxLines ?? this.maxLines,
430436
textOverflow: textOverflow ?? this.textOverflow,
437+
textTransform: textTransform ?? this.textTransform,
431438
);
432439
}
433440

@@ -447,6 +454,7 @@ class Style {
447454
this.textShadow = textStyle.shadows;
448455
this.wordSpacing = textStyle.wordSpacing;
449456
this.lineHeight = LineHeight(textStyle.height ?? 1.2);
457+
this.textTransform = TextTransform.none;
450458
}
451459
}
452460

@@ -561,6 +569,13 @@ enum ListStylePosition {
561569
INSIDE,
562570
}
563571

572+
enum TextTransform {
573+
uppercase,
574+
lowercase,
575+
capitalize,
576+
none,
577+
}
578+
564579
enum VerticalAlign {
565580
BASELINE,
566581
SUB,

0 commit comments

Comments
 (0)