feat: add list.markerMinWidth to align UL/OL/task lists#248
Merged
hryhoriiK97 merged 2 commits intosoftware-mansion-labs:mainfrom Apr 18, 2026
Merged
Conversation
…lists
Today each list type reserves its own natural marker column width — the
bullet radius (`bulletSize / 2`) for unordered, the width of `"99."` at
the marker font for ordered, and the checkbox size for tasks. Mixed
lists therefore look ragged: bullets and task boxes hang far to the left
of numbers.
The new optional `list.markerWidth` acts as a floor applied to all three
list types. Each list's effective column becomes `max(markerWidth,
natural)`, so consumers can widen the gutter uniformly without shrinking
ordered lists or resizing bullet/checkbox glyphs. Values below the
natural width are ignored.
```tsx
<EnrichedMarkdownText
markdownStyle={{
list: {
bulletSize: 6,
markerWidth: 22, // widens UL and task rows to match OL at 17pt
},
}}
...
/>
```
Implementation:
- Public `ListStyle.markerWidth?: number` (undefined = current
per-list-natural behavior).
- Internal codegen prop is a concrete `Float`; negative = "auto". Default
is set in `normalizeMarkdownStyle` so consumers never touch the
sentinel.
- iOS: `StyleConfig` now floors each list kind — new
`effectiveListMarginLeftForTask` plus updated
`effectiveListMarginLeftForBullet` / `effectiveListMarginLeftForNumber`.
`ListItemRenderer.m` routes the task case through the new accessor.
Wired through `StylePropsUtils` and included in the measurement cache
key so cached sizes invalidate when it changes.
- Android: `ListStyle.effectiveMarkerWidth(natural)` helper; each span
(`UnorderedListSpan`, `OrderedListSpan`, `TaskListSpan`) applies the
floor. Bullets and checkboxes now position themselves relative to the
reserved column's right edge so they line up flush with the gap —
behaviorally identical at the default since the column width equals
the natural glyph width.
- Docs: replaced the old bulletSize-only row in `docs/STYLES.md` with
the shared `markerWidth` semantics.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hryhoriiK97
requested changes
Apr 18, 2026
Collaborator
hryhoriiK97
left a comment
There was a problem hiding this comment.
@mozharovsky, thank you for the PR! It's a great improvement for the lists 💪 I've left a few comments. 🙂
…e 0 default Following review feedback from @hryhoriiK97: - Rename `list.markerWidth` → `list.markerMinWidth`: the name now carries the floor semantic ("at least this wide"), no room to read it as a hard-set width. - Default is `0` instead of a `-1` sentinel. Floor semantics make this trivial: `max(0, natural) === natural`, so no magic value is needed. Drops the three `>= 0` / `< 0` guards across TS normalize, Android parse, and iOS effective accessors. - iOS `effectiveListMarginLeftFor*` collapse to single-line `MAX(...)`. - Android `effectiveMarkerWidth` uses idiomatic `coerceAtLeast`; the `fromReadableMap` parse is now one line. Dropped the redundant KDoc (function name says it all). - Move JSDoc onto the public `MarkdownStyle` type (where consumers hover it in their IDE); drop the note from `MarkdownStyleInternal` since the public doc now covers the contract. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Thanks for the thorough review, @hryhoriiK97 — all seven points accepted in d505e61. Summary:
Net diff from this commit: |
hryhoriiK97
approved these changes
Apr 18, 2026
Collaborator
hryhoriiK97
left a comment
There was a problem hiding this comment.
LGTM! Thank you for the contribution. @mozharovsky, markerMinWidth will be included in tomorrow’s nightly release.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What/Why?
Today each list kind reserves its own natural marker column width:
bulletSize / 2for unordered, the width of"99."at the marker font for ordered, and the checkbox size for tasks. Mixed content therefore looks ragged — bulleted rows sit far to the left of numbered rows, task rows to the left of both.This PR adds one optional style,
list.markerWidth, that acts as a minimum reserved marker column width applied to all three list kinds. Each list's effective column becomesmax(markerWidth, natural), so consumers can line up mixed lists without shrinking ordered lists or resizing the bullet/checkbox glyphs. Values below the natural width are ignored; leaving it unset preserves existing behavior.Implementation
ListStyle.markerWidth?: number(type-only; JSDoc on the internal type captures the sentinel contract).Float; negative = auto. Default is set innormalizeMarkdownStyleso consumers never touch the sentinel.StyleConfiggets a new ivar + getter/setter;effectiveListMarginLeftForBullet/effectiveListMarginLeftForNumberfloor bymarkerWidth; neweffectiveListMarginLeftForTaskhandles task rows. Wired throughStylePropsUtilsand included inMeasurementCacheso cached sizes invalidate when the prop changes.ListItemRenderer.mroutes the task case through the new accessor.ListStylecarries the field and exposeseffectiveMarkerWidth(natural).UnorderedListSpan,OrderedListSpan, andTaskListSpanall apply the floor. Bullets and checkboxes now position themselves relative to the reserved column's right edge (matching iOS), which stays pixel-identical when the column width equals the natural glyph width.docs/STYLES.md.apps/example/src/markdownStyles.tssetsmarkerWidth: 20so the feature is visible against the existing mixed-list sample content.Testing
sampleMarkdownwhich has mixed UL, OL, and task lists on both platforms.markerWidthis undefined (floor is below natural).Screenshots
Same mixed-list sample content (UL + OL + task rows from
sampleMarkdown.ts) rendered with and withoutmarkerWidth: 20.iOS (iPhone 17 Pro simulator)
markerWidth: 20Android (Pixel 3a API 34 emulator)
markerWidth: 20PR Checklist