Skip to content

Commit b8cf7dc

Browse files
fix: place task checkboxes after list loose is finalized (#4046)
Loose nested task lists could leave checkboxes outside <p> because checkbox placement used list.loose before spacer detection finished. Compute the final loose state first, then place checkboxes. Fixes #4045
1 parent 9552b6b commit b8cf7dc

3 files changed

Lines changed: 44 additions & 8 deletions

File tree

src/Tokenizer.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -416,9 +416,22 @@ export class _Tokenizer<ParserOutput = string, RendererOutput = string> {
416416
list.raw = list.raw.trimEnd();
417417

418418
// Item child tokens handled here at end because we needed to have the final item to trim it first
419+
// First pass: tokenize items and finalize list.loose from spacers before placing checkboxes
419420
for (const item of list.items) {
420421
this.lexer.state.top = false;
421422
item.tokens = this.lexer.blockTokens(item.text, []);
423+
424+
if (!list.loose) {
425+
// Check if list should be loose
426+
const spacers = item.tokens.filter(t => t.type === 'space');
427+
const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => this.rules.other.anyLine.test(t.raw));
428+
429+
list.loose = hasMultipleLineBreaks;
430+
}
431+
}
432+
433+
// Second pass: place task checkboxes using the final list.loose
434+
for (const item of list.items) {
422435
const itemToken = item.tokens[0];
423436
if (item.task && (itemToken?.type === 'text' || itemToken?.type === 'paragraph')) {
424437
// Remove checkbox markdown from item tokens
@@ -460,14 +473,6 @@ export class _Tokenizer<ParserOutput = string, RendererOutput = string> {
460473
} else if (item.task) {
461474
item.task = false;
462475
}
463-
464-
if (!list.loose) {
465-
// Check if list should be loose
466-
const spacers = item.tokens.filter(t => t.type === 'space');
467-
const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => this.rules.other.anyLine.test(t.raw));
468-
469-
list.loose = hasMultipleLineBreaks;
470-
}
471476
}
472477

473478
// Set all items to loose if list is loose
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<ul>
2+
<li><p><input disabled="" type="checkbox"> Prepare the project</p>
3+
<ul>
4+
<li><input disabled="" type="checkbox"> Install dependencies</li>
5+
<li><input checked="" disabled="" type="checkbox"> Update Marked</li>
6+
<li><input disabled="" type="checkbox"> Check the rendering</li>
7+
</ul>
8+
</li>
9+
<li><p><input checked="" disabled="" type="checkbox"> Run the tests</p>
10+
<ul>
11+
<li><p><input checked="" disabled="" type="checkbox"> Test lists</p>
12+
</li>
13+
<li><p><input disabled="" type="checkbox"> Test tables</p>
14+
<ul>
15+
<li><input disabled="" type="checkbox"> Test nested cases</li>
16+
</ul>
17+
</li>
18+
</ul>
19+
</li>
20+
</ul>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
* [ ] Prepare the project
2+
3+
* [ ] Install dependencies
4+
* [x] Update Marked
5+
* [ ] Check the rendering
6+
* [x] Run the tests
7+
8+
* [x] Test lists
9+
* [ ] Test tables
10+
11+
* [ ] Test nested cases

0 commit comments

Comments
 (0)