react-native-enriched-markdown-scaffold 0.7.4-scaffold.4 → 0.7.4-scaffold.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,8 @@
1
1
  package com.swmansion.enriched.markdown.spans
2
2
 
3
3
  import android.graphics.Paint
4
+ import android.text.Spanned
5
+ import android.text.style.ReplacementSpan
4
6
  import kotlin.math.ceil
5
7
  import kotlin.math.floor
6
8
  import android.text.style.LineHeightSpan as AndroidLineHeightSpan
@@ -18,10 +20,34 @@ class LineHeightSpan(
18
20
  v: Int,
19
21
  fm: Paint.FontMetricsInt?,
20
22
  ) {
21
- if (fm == null) return
23
+ if (fm == null || lineHeight <= 0) return
22
24
 
23
25
  val leading = lineHeight - ((-fm.ascent) + fm.descent)
26
+
27
+ // A ReplacementSpan on this line — inline math, or the placeholder MeasurementStore
28
+ // swaps in to measure it off the main thread — reports its own metrics from getSize().
29
+ // Shrinking those back down to the configured line height cuts the line box below what
30
+ // the span actually draws, and can drive descent negative so the next line starts above
31
+ // this one's baseline. Those lines are expanded only, never compressed; every other line
32
+ // keeps the exact clamp it had before. The lookup only runs on the rare negative-leading
33
+ // path, so the common case stays allocation-free.
34
+ if (leading <= 0 && hasSelfMeasuringSpan(text, start, end)) return
35
+
24
36
  fm.ascent -= ceil(leading / 2.0f).toInt()
25
37
  fm.descent += floor(leading / 2.0f).toInt()
26
38
  }
39
+
40
+ /**
41
+ * Images are excluded on purpose. Block images already keep this span off their range via
42
+ * `applyLineHeightSkippingImages`, and inline ones never touch the metrics at all, so
43
+ * letting them through here would change image layout instead of math layout.
44
+ */
45
+ private fun hasSelfMeasuringSpan(
46
+ text: CharSequence?,
47
+ start: Int,
48
+ end: Int,
49
+ ): Boolean {
50
+ val spanned = text as? Spanned ?: return false
51
+ return spanned.getSpans(start, end, ReplacementSpan::class.java).any { it !is ImageSpan }
52
+ }
27
53
  }
@@ -109,15 +109,18 @@ NSString *const TaskIndexAttribute = @"TaskIndex";
109
109
  style.firstLineHeadIndent = totalIndent;
110
110
  style.headIndent = totalIndent;
111
111
 
112
- if (lineHeightConfig > 0) {
113
- style.minimumLineHeight = lineHeightConfig;
114
- style.maximumLineHeight = lineHeightConfig;
115
- }
116
-
117
112
  NSMutableDictionary *attributesToApply = [metadata mutableCopy];
118
113
  attributesToApply[NSParagraphStyleAttributeName] = style;
119
114
 
120
115
  [output addAttributes:attributesToApply range:range];
116
+
117
+ // Line height goes through the shared helper so list items get the same math
118
+ // carve-out as paragraphs. Setting maximumLineHeight here directly would clamp
119
+ // the line fragment below the height an inline math attachment draws at, and the
120
+ // overflow paints over the neighbouring lines. applyLineHeight reads back the
121
+ // paragraph style we just applied, so the indents above survive, and it
122
+ // early-returns on a non-positive line height like the old guard did.
123
+ applyLineHeight(output, range, lineHeightConfig);
121
124
  }];
122
125
 
123
126
  if (isTask && isChecked) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-enriched-markdown-scaffold",
3
- "version": "0.7.4-scaffold.4",
3
+ "version": "0.7.4-scaffold.5",
4
4
  "description": "Markdown Text component for React Native",
5
5
  "main": "./lib/module/index",
6
6
  "module": "./lib/module/index",