Skip to content

Commit d2fccad

Browse files
authored
Merge branch 'main' into fix/android-preserve-inline-styles-during-ime-composition
2 parents 8e5bd89 + 502acc9 commit d2fccad

4 files changed

Lines changed: 38 additions & 8 deletions

File tree

android/src/main/java/com/swmansion/enriched/common/parser/EnrichedParser.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@ public static String toHtml(Spanned text) {
9494
String normalizedBlockQuote =
9595
normalizedCodeBlock.replaceAll("</blockquote>\\n<br>", "</blockquote>");
9696

97-
// Replace empty <p> tags (with or without style attributes) with <br>
98-
String normalizedHtml = normalizedBlockQuote.replaceAll("<p[^>]*></p>", "<br>");
97+
// Replace empty <p> tags with <br>, except when they carry text-align
98+
String normalizedHtml =
99+
normalizedBlockQuote.replaceAll("<p(?![^>]*text-align\\s*:)[^>]*></p>", "<br>");
99100

100101
return "<html>\n" + normalizedHtml + "</html>";
101102
}
@@ -593,7 +594,14 @@ private void handleEndTag(String tag) {
593594
if (tag.equalsIgnoreCase("br")) {
594595
handleBr(mSpannableStringBuilder);
595596
} else if (tag.equalsIgnoreCase("p")) {
597+
boolean empty = isEmptyTag;
598+
Alignment pendingAlignment = empty ? getLast(mSpannableStringBuilder, Alignment.class) : null;
596599
endBlockElement(mSpannableStringBuilder, mSpanFactory);
600+
// Plain empty paragraphs never reach setParagraphSpanFromMark (no ZWS).
601+
// Represent them as a blank line so they round-trip as <br>.
602+
if (empty && pendingAlignment == null) {
603+
handleBr(mSpannableStringBuilder);
604+
}
597605
} else if (tag.equalsIgnoreCase("ul")) {
598606
currentListAlignmentCssValue = null;
599607
endBlockElement(mSpannableStringBuilder, mSpanFactory);

android/src/main/java/com/swmansion/enriched/common/spans/EnrichedInlineCodeSpan.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,21 @@ open class EnrichedInlineCodeSpan(
1111
) : MetricAffectingSpan(),
1212
EnrichedInlineSpan {
1313
override fun updateDrawState(textPaint: TextPaint) {
14-
val typeface = Typeface.create(Typeface.MONOSPACE, Typeface.NORMAL)
15-
textPaint.typeface = typeface
14+
applyMonospace(textPaint)
1615
textPaint.color = enrichedStyle.inlineCodeColor
1716
textPaint.bgColor = enrichedStyle.inlineCodeBackgroundColor
1817
}
1918

2019
override fun updateMeasureState(textPaint: TextPaint) {
21-
val typeface = Typeface.create(Typeface.MONOSPACE, Typeface.NORMAL)
20+
applyMonospace(textPaint)
21+
}
22+
23+
// When switching to a monospace font, we need to remember
24+
// and apply other current styles, such as bold or italic.
25+
private fun applyMonospace(textPaint: TextPaint) {
26+
val currentStyle = textPaint.typeface?.style ?: Typeface.NORMAL
27+
val typeface = Typeface.create(Typeface.MONOSPACE, currentStyle)
28+
2229
textPaint.typeface = typeface
2330
}
2431
}

android/src/main/java/com/swmansion/enriched/textinput/styles/InlineStyles.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class InlineStyles(
1818
) {
1919
val previousSpanStart = (start - 1).coerceAtLeast(0)
2020
val previousSpanEnd = previousSpanStart + 1
21-
val nextSpanStart = (end + 1).coerceAtMost(spannable.length)
21+
val nextSpanStart = end.coerceAtMost(spannable.length)
2222
val nextSpanEnd = (nextSpanStart + 1).coerceAtMost(spannable.length)
2323
val previousSpans = spannable.getSpans(previousSpanStart, previousSpanEnd, type)
2424
val nextSpans = spannable.getSpans(nextSpanStart, nextSpanEnd, type)

ios/htmlParser/HtmlParser.mm

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,16 @@ + (NSString *)parseToHtmlFromRange:(NSRange)range
957957
inCheckboxList = NO;
958958
}
959959
} else {
960-
[result appendString:@"\n<br>"];
960+
NSString *cssStyleString =
961+
[self prepareCssStyleString:currentRange.location
962+
isOpeningTag:YES
963+
host:host];
964+
if (cssStyleString.length > 0) {
965+
[result appendString:[NSString stringWithFormat:@"\n<p%@></p>",
966+
cssStyleString]];
967+
} else {
968+
[result appendString:@"\n<br>"];
969+
}
961970
}
962971
} else {
963972
// newline finishes a paragraph and all style tags need to be closed
@@ -1456,7 +1465,7 @@ + (NSString *)prepareCssStyleString:(NSInteger)location
14561465
}
14571466

14581467
+ (void)checkForAlignments:(NSArray *)tagData
1459-
plainText:(NSString *)plainText
1468+
plainText:(NSMutableString *)plainText
14601469
foundAlignments:(NSMutableArray<AlignmentEntry *> *)foundAlignments
14611470
precedingImageCount:(NSInteger)precedingImageCount {
14621471
if (tagData == nil) {
@@ -1474,6 +1483,12 @@ + (void)checkForAlignments:(NSArray *)tagData
14741483
NSInteger actualStart = startLoc + precedingImageCount;
14751484
NSInteger length = plainText.length - startLoc;
14761485

1486+
// Empty aligned paragraphs have no characters to attach alignment to.
1487+
if (length == 0) {
1488+
[plainText appendString:@"\u200B"];
1489+
length = 1;
1490+
}
1491+
14771492
if (length > 0) {
14781493
AlignmentEntry *entry = [[AlignmentEntry alloc] init];
14791494
entry.alignment = align;

0 commit comments

Comments
 (0)