diff --git a/.changeset/unwrap-list-item-paragraphs.md b/.changeset/unwrap-list-item-paragraphs.md new file mode 100644 index 00000000..25b91a49 --- /dev/null +++ b/.changeset/unwrap-list-item-paragraphs.md @@ -0,0 +1,9 @@ +--- +"streamdown": patch +--- + +fix: unwrap a single paragraph child inside list items + +Loose list items from the markdown pipeline are often wrapped in a `
`. `MemoLi` now detects that sole paragraph child (including the memoized paragraph component) and renders its contents directly, so list items stay visually tight. Also updates the list animation retrigger test to match the unwrapped markup. + +Fixes #475 diff --git a/packages/streamdown/__tests__/list-animation-retrigger.test.tsx b/packages/streamdown/__tests__/list-animation-retrigger.test.tsx index 946c900c..46a7455e 100644 --- a/packages/streamdown/__tests__/list-animation-retrigger.test.tsx +++ b/packages/streamdown/__tests__/list-animation-retrigger.test.tsx @@ -66,10 +66,11 @@ describe("list animation retrigger fix (#410)", () => { // There should be MORE spans after (new item appeared) expect(afterSpans.length).toBeGreaterThan(initialSpans.length); - // The list is loose once a second group appears, so the items are rebuilt - // around a
. What must not happen is the already-visible text re-running - // its entry animation: those characters carry --sd-duration:0ms. - expect(container.querySelector("li > p")).toBeTruthy(); + // The list is loose once a second group appears, so rehype rebuilds items + // around a
; MemoLi then unwraps a single paragraph child. What must not
+ // happen is the already-visible text re-running its entry animation: those
+ // characters carry --sd-duration:0ms.
+ expect(container.querySelector("li > p")).toBeNull();
// One character at the transition boundary is not suppressed:
// prevContentLength counts inter-element whitespace, and the tight -> loose
diff --git a/packages/streamdown/__tests__/list-item-paragraphs.test.tsx b/packages/streamdown/__tests__/list-item-paragraphs.test.tsx
new file mode 100644
index 00000000..4ba9b5cf
--- /dev/null
+++ b/packages/streamdown/__tests__/list-item-paragraphs.test.tsx
@@ -0,0 +1,23 @@
+import { render } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+import { Streamdown } from "../index";
+
+describe("list item paragraph wrapping", () => {
+ it("does not keep paragraph wrappers for loose list items", () => {
+ const markdown = `
+## Test
+
+- hello
+
+- world
+`;
+ const { container } = render(