Skip to content

fix(android): toggle the tapped task item after a table, code block or quote - #1077

Merged
jnowakow merged 3 commits into
mainfrom
fix/rn-android-task-index-across-segments
Oct 27, 2026
Merged

jnowakow merged 3 commits into
mainfrom
fix/rn-android-task-index-across-segments

Conversation

@jnowakow

@jnowakow jnowakow commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

What/Why?

In the GitHub flavor, tapping a task checkbox after a table, code block or blockquote toggled the wrong item. Each text segment (and each blockquote container) numbered its tasks from 0, so the tap toggled the Nth task of the whole document with a per-segment index.

  • Task indices now continue across segments (startingTaskIndex / getTaskItemCount(), ported from enriched-markdown-android). Blockquote containers get their starting index too.
  • A segment with tasks mixes its first task index into its signature, so it gets updated when tasks are added or removed earlier in the document.
  • toggleAtIndex now also counts tasks behind > and ordered tasks (1. [ ]), so its Nth task matches the renderer's.

Known gaps, not changed here. toggleAtIndex scans the source, so it still counts two kinds of lines the parser doesn't treat as tasks:

  • - [ ] lines inside fenced code blocks.
  • An ordered item that doesn't start at 1 inside a paragraph, like 2. [ ] on the line after text. The parser doesn't allow it to interrupt the paragraph.

iOS has the same per-segment restart.

Testing

Playground, "Reference links: Off" (GitHub flavor), Set Raw Markdown:

- [ ] one
- [ ] two

| a | b |
|---|---|
| 1 | 2 |

- [ ] three

```js
const x = 1;
```

- [ ] four

> - [ ] five
> - [ ] six

- [ ] seven

Tap each checkbox after the table. Before: it toggles "one" or "two". After: it toggles the tapped item.

Before After
before table after table
before quote after quote

PR Checklist

  • Code compiles and runs on iOS (iOS not touched)
  • Code compiles and runs on Android
  • Updated documentation/README if applicable
  • Ran example app to verify changes
  • E2E tests are passing
  • Required E2E tests have been added (if applicable)

…r quote

In the GitHub flavor each text segment rendered with a fresh Renderer, so
task indices restarted at 0 after every table, code block or blockquote,
while the toggle rewrites the Nth task of the whole markdown source. Tapping
a later task checked an earlier one.

Port the library's fix (packages/enriched-markdown-android, #806):
Renderer.renderContent takes a startingTaskIndex and reports
getTaskItemCount(), and MarkdownSegmentRenderer threads a running
taskIndexOffset through its text segments. RN also renders blockquotes as
containers, so a Blockquote segment carries its first task index into its
own render, and the count continues after it. A segment holding tasks mixes
its first index into its signature, so a reused view never keeps stale
indices when earlier tasks change.

TaskListToggleUtils now also counts tasks behind `>` quote markers and in
ordered lists, which the renderer numbers too.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The expanded source matcher still counts non-task text as tasks, causing checkbox taps to modify the wrong source line.

2 open issues
What changed in this PR

This PR fixes Android task-checkbox targeting across text segments separated by tables, code blocks, and blockquotes.

Changes:

  • Carries document-wide task indices through rendering and blockquote views.
  • Updates segment signatures when earlier tasks change their indices.
  • Expands source matching for quoted and ordered tasks and adds regression tests.
File Description
packages/​react-native-enriched-markdown/​android/​src/​test/​java/​com/​swmansion/​enriched/​markdown/​test/​MarkdownRenderTestSupport.kt Adds heading styles needed by segment tests.
packages/​react-native-enriched-markdown/​android/​src/​test/​java/​com/​swmansion/​enriched/​markdown/​segments/​TaskIndexAcrossSegmentsTest.kt Tests task indexing, signatures, and source toggling.
packages/​react-native-enriched-markdown/​android/​src/​main/​java/​com/​swmansion/​enriched/​markdown/​utils/​text/​interaction/​TaskListTapUtils.kt Matches quoted and ordered task markers.
packages/​react-native-enriched-markdown/​android/​src/​main/​java/​com/​swmansion/​enriched/​markdown/​segments/​SegmentViewCreators.kt Passes task offsets to new blockquote views.
packages/​react-native-enriched-markdown/​android/​src/​main/​java/​com/​swmansion/​enriched/​markdown/​segments/​SegmentSignature.kt Incorporates task offsets into signatures.
packages/​react-native-enriched-markdown/​android/​src/​main/​java/​com/​swmansion/​enriched/​markdown/​segments/​RenderedSegment.kt Tracks task indices across segments.
packages/​react-native-enriched-markdown/​android/​src/​main/​java/​com/​swmansion/​enriched/​markdown/​segments/​BlockquoteContainerView.kt Propagates offsets through blockquote rendering and updates.
packages/​react-native-enriched-markdown/​android/​src/​main/​java/​com/​swmansion/​enriched/​markdown/​renderer/​Renderer.kt Supports starting indices and exposes the task counter.
packages/​react-native-enriched-markdown/​android/​src/​main/​java/​com/​swmansion/​enriched/​markdown/​renderer/​BlockquoteTextRenderer.kt Forwards starting task indices.
packages/​react-native-enriched-markdown/​android/​src/​main/​java/​com/​swmansion/​enriched/​markdown/​EnrichedMarkdown.kt Preserves task offsets when updating blockquotes.

Review effort: Balanced

// A task item's line: any blockquote markers (`>`), then a bullet or ordered-list marker, then
// the checkbox. It must find every task the renderer numbers, in document order, or
// [toggleAtIndex] rewrites a different item than the one tapped.
private val TASK_PATTERN = Regex("""^((?:[ \t]*>)*[ \t]*(?:[-*+]|\d{1,9}[.)])[ \t]+)\[[ xX]]""", RegexOption.MULTILINE)
// A task item's line: any blockquote markers (`>`), then a bullet or ordered-list marker, then
// the checkbox. It must find every task the renderer numbers, in document order, or
// [toggleAtIndex] rewrites a different item than the one tapped.
private val TASK_PATTERN = Regex("""^((?:[ \t]*>)*[ \t]*(?:[-*+]|\d{1,9}[.)])[ \t]+)\[[ xX]]""", RegexOption.MULTILINE)
@jnowakow
jnowakow requested a review from maksg October 27, 2026 11:17
@jnowakow
jnowakow marked this pull request as ready for review October 27, 2026 11:17
@jnowakow
jnowakow merged commit 3cc2042 into main Oct 27, 2026
19 checks passed
@jnowakow
jnowakow deleted the fix/rn-android-task-index-across-segments branch October 27, 2026 12:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants