Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class OrderedListSpan(

override fun getMarkerWidth(): Float {
val paint = configureMarkerPaint()
return paint.measureText("99.")
return listStyle.effectiveMarkerWidth(paint.measureText("99."))
}

var itemNumber: Int = 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import com.swmansion.enriched.markdown.styles.TaskListStyle

class TaskListSpan(
private val taskStyle: TaskListStyle,
listStyle: ListStyle,
private val listStyle: ListStyle,
depth: Int,
context: Context,
styleCache: SpanStyleCache,
Expand All @@ -34,6 +34,7 @@ class TaskListSpan(
gapWidth = listStyle.gapWidth,
) {
private val checkboxSize = taskStyle.checkboxSize
private val markerColumnWidth = listStyle.effectiveMarkerWidth(checkboxSize)
private val cornerRadius = taskStyle.checkboxBorderRadius
private val rect = RectF()
private val checkPath = Path()
Expand All @@ -55,7 +56,7 @@ class TaskListSpan(
strokeJoin = Paint.Join.ROUND
}

override fun getMarkerWidth(): Float = checkboxSize
override fun getMarkerWidth(): Float = markerColumnWidth

override fun drawMarker(
canvas: Canvas,
Expand All @@ -71,7 +72,10 @@ class TaskListSpan(
val fontMetrics = paint.fontMetrics
val capHeight = -fontMetrics.ascent * CAP_HEIGHT_RATIO
val centerY = baseline - capHeight / HALF_DIVISOR
val centerX = x + (depth * marginLeft + checkboxSize / HALF_DIVISOR) * dir
// Right-align the checkbox inside the reserved marker column so it hugs
// the gap before the text. At the default (markerColumnWidth ==
// checkboxSize) this is identical to the previous flush-left layout.
val centerX = x + (depth * marginLeft + markerColumnWidth - checkboxSize / HALF_DIVISOR) * dir
val half = checkboxSize / HALF_DIVISOR
rect.set(centerX - half, centerY - half, centerX + half, centerY + half)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ class UnorderedListSpan(
}

private val radius: Float = listStyle.bulletSize / 2f
private val markerColumnWidth: Float = listStyle.effectiveMarkerWidth(radius)

private fun configureBulletPaint(): Paint =
sharedBulletPaint.apply {
color = listStyle.bulletColor
}

override fun getMarkerWidth(): Float = radius
override fun getMarkerWidth(): Float = markerColumnWidth

override fun drawMarker(
canvas: Canvas,
Expand All @@ -55,7 +56,11 @@ class UnorderedListSpan(
start: Int,
) {
val bulletPaint = configureBulletPaint()
val bulletX = x + (depth * marginLeft + radius) * dir
// Center the bullet at the right edge of the reserved marker column so
// it hugs the gap before the text — matches iOS behavior and stays
// visually flush-left when the column width equals the bullet radius
// (the default).
val bulletX = x + (depth * marginLeft + markerColumnWidth) * dir
val fontMetrics = paint.fontMetrics
val bulletY = baseline + (fontMetrics.ascent + fontMetrics.descent) / 2f

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ data class ListStyle(
override val lineHeight: Float,
val bulletColor: Int,
val bulletSize: Float,
val markerWidth: Float,
val markerColor: Int,
val markerFontWeight: String,
val gapWidth: Float,
val marginLeft: Float,
) : BaseBlockStyle {

/** Floor `naturalWidth` by the consumer-configured `markerWidth`. */
fun effectiveMarkerWidth(naturalWidth: Float): Float =
if (markerWidth > naturalWidth) markerWidth else naturalWidth
Comment thread
hryhoriiK97 marked this conversation as resolved.
Outdated

companion object {
fun fromReadableMap(
map: ReadableMap,
Expand All @@ -32,6 +38,13 @@ data class ListStyle(
val lineHeight = parser.toPixelFromSP(lineHeightRaw)
val bulletColor = parser.parseColor(map, "bulletColor")
val bulletSize = parser.toPixelFromDIP(map.getDouble("bulletSize").toFloat())
val markerWidthRaw = map.getDouble("markerWidth").toFloat()
val markerWidth =
if (markerWidthRaw < 0f) {
-1f
} else {
parser.toPixelFromDIP(markerWidthRaw)
}
Comment thread
hryhoriiK97 marked this conversation as resolved.
Outdated
val markerColor = parser.parseColor(map, "markerColor")
val markerFontWeight = parser.parseString(map, "markerFontWeight", "normal")
val gapWidth = parser.toPixelFromDIP(map.getDouble("gapWidth").toFloat())
Expand All @@ -47,6 +60,7 @@ data class ListStyle(
lineHeight,
bulletColor,
bulletSize,
markerWidth,
markerColor,
markerFontWeight,
gapWidth,
Expand Down
1 change: 1 addition & 0 deletions apps/example/src/markdownStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export const customMarkdownStyle: MarkdownStyle = {
lineHeight: Platform.select({ ios: 22, android: 26, default: 26 }),
bulletColor: '#6b7280',
bulletSize: 6,
markerWidth: 20,
markerColor: '#6b7280',
markerFontWeight: '500',
gapWidth: 8,
Expand Down
1 change: 1 addition & 0 deletions docs/STYLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ The library provides sensible default styles for all Markdown elements out of th
|----------|------|-------------|
| `bulletColor` | `string` | Bullet point color |
| `bulletSize` | `number` | Bullet point size |
| `markerWidth` | `number` | Minimum reserved marker column width (floors the natural width of every list type) |
| `markerColor` | `string` | Number marker color |
| `markerFontWeight` | `string` | Number marker font weight |
| `gapWidth` | `number` | Gap between marker and text |
Expand Down
2 changes: 1 addition & 1 deletion ios/internals/MeasurementCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ template <typename StyleStruct> inline size_t computeStyleFingerprint(const Styl
hashFields(s.blockquote.borderWidth, s.blockquote.gapWidth);

hashTextLayout(s.list);
hashFields(s.list.bulletSize, s.list.markerFontWeight, s.list.gapWidth, s.list.marginLeft);
hashFields(s.list.bulletSize, s.list.markerWidth, s.list.markerFontWeight, s.list.gapWidth, s.list.marginLeft);

// Code & Inlines
hashFields(s.codeBlock.fontFamily, s.codeBlock.fontSize, s.codeBlock.fontWeight, s.codeBlock.marginTop,
Expand Down
2 changes: 1 addition & 1 deletion ios/renderer/ListItemRenderer.m
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)out

// currentDepth - 1 handles the horizontal offset for nested lists
const NSInteger nestingLevel = currentDepth - 1;
const CGFloat baseMarkerWidth = isTask ? [_config taskListCheckboxSize]
const CGFloat baseMarkerWidth = isTask ? [_config effectiveListMarginLeftForTask]
: (context.listType == ListTypeOrdered) ? [_config effectiveListMarginLeftForNumber]
: [_config effectiveListMarginLeftForBullet];

Expand Down
3 changes: 3 additions & 0 deletions ios/styles/StyleConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@
- (void)setListStyleBulletColor:(RCTUIColor *)newValue;
- (CGFloat)listStyleBulletSize;
- (void)setListStyleBulletSize:(CGFloat)newValue;
- (CGFloat)listStyleMarkerWidth;
- (void)setListStyleMarkerWidth:(CGFloat)newValue;
- (RCTUIColor *)listStyleMarkerColor;
- (void)setListStyleMarkerColor:(RCTUIColor *)newValue;
- (NSString *)listStyleMarkerFontWeight;
Expand All @@ -249,6 +251,7 @@
- (CGFloat)effectiveListGapWidth;
- (CGFloat)effectiveListMarginLeftForBullet;
- (CGFloat)effectiveListMarginLeftForNumber;
- (CGFloat)effectiveListMarginLeftForTask;
// Code block properties
- (CGFloat)codeBlockFontSize;
- (void)setCodeBlockFontSize:(CGFloat)newValue;
Expand Down
34 changes: 30 additions & 4 deletions ios/styles/StyleConfig.mm
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ @implementation StyleConfig {
CGFloat _listStyleLineHeight;
RCTUIColor *_listStyleBulletColor;
CGFloat _listStyleBulletSize;
CGFloat _listStyleMarkerWidth;
RCTUIColor *_listStyleMarkerColor;
NSString *_listStyleMarkerFontWeight;
CGFloat _listStyleGapWidth;
Expand Down Expand Up @@ -434,6 +435,7 @@ - (id)copyWithZone:(NSZone *)zone
copy->_listStyleLineHeight = _listStyleLineHeight;
copy->_listStyleBulletColor = [_listStyleBulletColor copy];
copy->_listStyleBulletSize = _listStyleBulletSize;
copy->_listStyleMarkerWidth = _listStyleMarkerWidth;
copy->_listStyleMarkerColor = [_listStyleMarkerColor copy];
copy->_listStyleMarkerFontWeight = [_listStyleMarkerFontWeight copy];
copy->_listStyleGapWidth = _listStyleGapWidth;
Expand Down Expand Up @@ -1706,6 +1708,16 @@ - (void)setListStyleBulletSize:(CGFloat)newValue
_listStyleBulletSize = newValue;
}

- (CGFloat)listStyleMarkerWidth
{
return _listStyleMarkerWidth;
}

- (void)setListStyleMarkerWidth:(CGFloat)newValue
{
_listStyleMarkerWidth = newValue;
}

- (RCTUIColor *)listStyleMarkerColor
{
return _listStyleMarkerColor;
Expand Down Expand Up @@ -1786,16 +1798,30 @@ - (CGFloat)effectiveListGapWidth

- (CGFloat)effectiveListMarginLeftForBullet
{
// Just the minimum width needed for bullet (radius)
return _listStyleBulletSize / 2.0;
// Natural width for a bullet is the bullet radius (bulletSize / 2). The
// consumer-provided `markerWidth` acts as a floor so bulleted lists can
// line up with ordered / task lists without resizing the bullet glyph.
CGFloat natural = _listStyleBulletSize / 2.0;
return _listStyleMarkerWidth > natural ? _listStyleMarkerWidth : natural;
}

- (CGFloat)effectiveListMarginLeftForNumber
{
// Reserve width for numbers up to 99 (matching Android)
// Reserve width for numbers up to 99 (matching Android). `markerWidth`
// floors the value so consumers can widen the column uniformly.
UIFont *font = [self listMarkerFont];
return
CGFloat natural =
[@"99." sizeWithAttributes:@{NSFontAttributeName : font ?: [UIFont systemFontOfSize:_listStyleFontSize]}].width;
return _listStyleMarkerWidth > natural ? _listStyleMarkerWidth : natural;
}

- (CGFloat)effectiveListMarginLeftForTask
{
// Task checkbox reserves at least its own size. `markerWidth` can widen
// the column so task rows align with adjacent UL/OL rows. The checkbox
// glyph itself is still drawn at its configured size.
CGFloat natural = [self taskListCheckboxSize];
return _listStyleMarkerWidth > natural ? _listStyleMarkerWidth : natural;
Comment thread
hryhoriiK97 marked this conversation as resolved.
Outdated
}

// Code block properties
Expand Down
5 changes: 5 additions & 0 deletions ios/utils/StylePropsUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,11 @@ BOOL applyMarkdownStyleToConfig(StyleConfig *config, const MarkdownStyle &newSty
changed = YES;
}

if (newStyle.list.markerWidth != oldStyle.list.markerWidth) {
[config setListStyleMarkerWidth:newStyle.list.markerWidth];
changed = YES;
}

if (newStyle.list.markerColor != oldStyle.list.markerColor) {
RCTUIColor *markerColor = RCTUIColorFromSharedColor(newStyle.list.markerColor);
[config setListStyleMarkerColor:markerColor];
Expand Down
1 change: 1 addition & 0 deletions src/EnrichedMarkdownNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ interface BlockquoteStyleInternal extends BaseBlockStyleInternal {
interface ListStyleInternal extends BaseBlockStyleInternal {
bulletColor: ColorValue;
bulletSize: CodegenTypes.Float;
markerWidth: CodegenTypes.Float;
markerColor: ColorValue;
markerFontWeight: string;
gapWidth: CodegenTypes.Float;
Expand Down
1 change: 1 addition & 0 deletions src/EnrichedMarkdownTextNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ interface BlockquoteStyleInternal extends BaseBlockStyleInternal {
interface ListStyleInternal extends BaseBlockStyleInternal {
bulletColor: ColorValue;
bulletSize: CodegenTypes.Float;
markerWidth: CodegenTypes.Float;
markerColor: ColorValue;
markerFontWeight: string;
gapWidth: CodegenTypes.Float;
Expand Down
1 change: 1 addition & 0 deletions src/normalizeMarkdownStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ const DEFAULT_NORMALIZED_STYLE = Object.freeze({
marginBottom: 16,
bulletColor: normalizeColor('#6B7280')!,
bulletSize: 6,
markerWidth: -1,
Comment thread
hryhoriiK97 marked this conversation as resolved.
Outdated
markerColor: normalizeColor('#6B7280')!,
markerFontWeight: '500',
gapWidth: 12,
Expand Down
1 change: 1 addition & 0 deletions src/normalizeMarkdownStyle.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const DEFAULT_NORMALIZED_STYLE: MarkdownStyleInternal = Object.freeze({
marginBottom: 16,
bulletColor: '#6B7280',
bulletSize: 6,
markerWidth: -1,
markerColor: '#6B7280',
markerFontWeight: '500',
gapWidth: 12,
Expand Down
1 change: 1 addition & 0 deletions src/types/MarkdownStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ interface BlockquoteStyle extends BaseBlockStyle {
interface ListStyle extends BaseBlockStyle {
bulletColor?: string;
bulletSize?: number;
markerWidth?: number;
Comment thread
hryhoriiK97 marked this conversation as resolved.
Outdated
markerColor?: string;
markerFontWeight?: string;
gapWidth?: number;
Expand Down
4 changes: 4 additions & 0 deletions src/types/MarkdownStyleInternal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ interface BlockquoteStyleInternal extends BaseBlockStyleInternal {
interface ListStyleInternal extends BaseBlockStyleInternal {
bulletColor: string;
bulletSize: number;
// Minimum reserved marker column width. Negative = "auto" → use each
// list's natural marker width (UL: bulletSize/2, OL: width of "99.",
// task: checkbox size).
Comment thread
hryhoriiK97 marked this conversation as resolved.
Outdated
markerWidth: number;
Comment thread
hryhoriiK97 marked this conversation as resolved.
Outdated
markerColor: string;
markerFontWeight: string;
gapWidth: number;
Expand Down
Loading