diff --git a/apps/web/src/components/ChatMarkdown.test.tsx b/apps/web/src/components/ChatMarkdown.test.tsx index 9499ee5a6915..a8c82552f9bb 100644 --- a/apps/web/src/components/ChatMarkdown.test.tsx +++ b/apps/web/src/components/ChatMarkdown.test.tsx @@ -24,13 +24,21 @@ describe("orderedListGutterStyle", () => { it("accounts for a non-default start attribute", () => { // start=95 + 9 items => last marker is "103", three digits. expect(orderedListGutterStyle(9, 95)).toEqual({ "--list-gutter": "4ch" }); + expect(orderedListGutterStyle(5, "999995")).toEqual({ "--list-gutter": "7ch" }); }); it("scales further for four-digit markers", () => { expect(orderedListGutterStyle(1000, undefined)).toEqual({ "--list-gutter": "5ch" }); }); + it("uses the widest marker and includes a negative start's minus sign", () => { + expect(orderedListGutterStyle(1001, -1000)).toEqual({ "--list-gutter": "6ch" }); + expect(orderedListGutterStyle(3, -15)).toEqual({ "--list-gutter": "4ch" }); + expect(orderedListGutterStyle(3, -5)).toBeUndefined(); + }); + it("treats a missing/zero item count as a single item", () => { expect(orderedListGutterStyle(0, undefined)).toBeUndefined(); + expect(orderedListGutterStyle(0, 100)).toEqual({ "--list-gutter": "4ch" }); }); }); diff --git a/apps/web/src/components/ChatMarkdown.tsx b/apps/web/src/components/ChatMarkdown.tsx index c3e1c5288da7..74cc76afd498 100644 --- a/apps/web/src/components/ChatMarkdown.tsx +++ b/apps/web/src/components/ChatMarkdown.tsx @@ -157,22 +157,24 @@ function findTaskListMarkerOffset(markdown: string, listItemStart: number): numb } /** - * The default `1.25rem` marker gutter (`.chat-markdown ol`) fits two-digit - * decimal markers. Once a list's last item reaches three digits (item 100+), - * `list-style-position: outside` paints the marker wider than that gutter and - * the leading digit gets clipped by the item's own overflow. Rather than - * widening the gutter for every list, only lists whose last marker is 3+ - * digits get a wider `--list-gutter`, sized to that marker's digit count. + * The default `1.25rem` marker gutter (`.chat-markdown ol`) fits markers up to + * two characters wide. Once a marker reaches three characters (item 100+), + * `list-style-position: outside` paints it wider than that gutter and clips + * the leading character against the item's own overflow. Rather than widening + * the gutter for every list, only lists whose widest marker is 3+ characters + * get a wider `--list-gutter`. The width includes a negative marker's minus + * sign. */ export function orderedListGutterStyle( itemCount: number, - start: number | undefined, + start: unknown, ): { "--list-gutter": string } | undefined { - const firstNumber = typeof start === "number" && Number.isFinite(start) ? start : 1; + const parsedStart = Number.parseInt(String(start ?? 1), 10); + const firstNumber = Number.isNaN(parsedStart) ? 1 : parsedStart; const lastNumber = firstNumber + Math.max(itemCount - 1, 0); - const digits = String(Math.abs(lastNumber)).length; - if (digits <= 2) return undefined; - return { "--list-gutter": `${digits + 1}ch` }; + const markerWidth = Math.max(String(firstNumber).length, String(lastNumber).length); + if (markerWidth <= 2) return undefined; + return { "--list-gutter": `${markerWidth + 1}ch` }; } const CHAT_MARKDOWN_SANITIZE_SCHEMA = { diff --git a/apps/web/src/index.css b/apps/web/src/index.css index b602758d09ca..63751f589019 100644 --- a/apps/web/src/index.css +++ b/apps/web/src/index.css @@ -2040,7 +2040,7 @@ code { /* --list-gutter defaults to the same 1.25rem as .chat-markdown ul, but ChatMarkdown's `ol` renderer widens it (via inline style) for lists whose - last marker is 3+ digits, so item 100+ isn't clipped by list-style-position: + widest marker is 3+ characters, so item 100+ isn't clipped by list-style-position: outside painting the marker past the padding box. Reset it here too so a nested ol without its own widened marker doesn't inherit the outer one. */ .chat-markdown ol { @@ -2049,6 +2049,10 @@ code { list-style-type: decimal; } +.chat-markdown ol > li::marker { + font-variant-numeric: tabular-nums; +} + .chat-markdown ul ul { list-style-type: circle; } @@ -2114,7 +2118,6 @@ code { .chat-markdown section[data-footnotes] ol { margin: 0; - padding-left: 1.25rem; } .chat-markdown section[data-footnotes] li + li {