diff --git a/docs/guide/syntax.md b/docs/guide/syntax.md index bc22957b..8110f343 100644 --- a/docs/guide/syntax.md +++ b/docs/guide/syntax.md @@ -575,6 +575,57 @@ With `nestedListsWithoutBlankLine` mode enabled, nested lists can appear immedia See the [Parser Options guide](/guide/parser-options#nested-lists-without-blank-line-mode) for more on `nestedListsWithoutBlankLine` mode. +#### Compact List Blocks + +::: warning djot-php divergence +By default djot-php keeps a list **tight** when an item carries a sub-block. +Canonical djot renders such a list **loose**. This changes only the tight/loose +rendering, never the block structure, so it does not affect the uniformity +principle — but the HTML differs from djot.js for these inputs. +::: + +In standard djot, a block inside a list item needs a blank line before it, and +that blank line makes the whole list **loose** (every item gets `
` wrappers). +So any list whose items carry a sub-block is forced loose. djot-php avoids this: +the blank line still **starts** the block, but no longer **loosens** the list +when the indented content opens a block (sub-list, block quote, fenced code, +fenced div, heading, table). The item stays tight, with its lead text inline. + +```djot +- Deploy the service + + > Needs the new env vars set first +- Run migrations +``` + +renders a **tight** list (lead text inline, the quote attached to its item): + +```html +
++Needs the new env vars set first
+
. + $this->assertStringContainsString("
", $html); + $this->assertStringNotContainsString('item
', $html); + } + + public function testFencedCodeAfterBlankStaysTight(): void + { + $html = $this->converter->convert("- run\n\n ```\n make\n ```\n- next"); + $this->assertStringContainsString("\nrun\n ", $html); + $this->assertStringNotContainsString('run
', $html); + } + + public function testHeadingAfterBlankStaysTight(): void + { + $html = $this->converter->convert("- section\n\n # Title\n- next"); + $this->assertStringContainsString("\nsection\n", $html); + $this->assertStringNotContainsString(' section
', $html); + } + + public function testSublistAfterBlankStaysTight(): void + { + $html = $this->converter->convert("- parent\n\n - child\n- next"); + $this->assertStringNotContainsString('parent
', $html); + } + + public function testSecondProseParagraphStillLoosens(): void + { + // A real second paragraph in the item is still a loose list. + $html = $this->converter->convert("- item\n\n second paragraph\n- next"); + $this->assertStringContainsString('item
', $html); + $this->assertStringContainsString('second paragraph
', $html); + } + + public function testBlankLineBetweenItemsStillLoosens(): void + { + $html = $this->converter->convert("- a\n\n- b"); + $this->assertStringContainsString('a
', $html); + $this->assertStringContainsString('b
', $html); + } +} diff --git a/tests/TestCase/Converter/HtmlToDjotTest.php b/tests/TestCase/Converter/HtmlToDjotTest.php index 8babff03..c0708836 100644 --- a/tests/TestCase/Converter/HtmlToDjotTest.php +++ b/tests/TestCase/Converter/HtmlToDjotTest.php @@ -722,7 +722,9 @@ public function testListItemWithBlockquoteKeepsNestedBlockquote(): void $this->assertSame("- One\n\n > Quote\n", $result); $htmlBack = (new DjotConverter())->convert($result); - $this->assertStringContainsString("\n One
\n", $htmlBack); + // Compact-list-blocks: a blank line before a sub-block no longer loosens + // the item, so the lead text renders inline (tight), not wrapped in. + $this->assertStringContainsString("
\nOne\n ", $htmlBack); $this->assertStringContainsString('Quote
', $htmlBack); }