Skip to content

Commit 2c4158f

Browse files
abcdmkuclaude
andauthored
fix(web): handle wide ordered-list marker edge cases (#7856)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 0ede2ed commit 2c4158f

3 files changed

Lines changed: 26 additions & 13 deletions

File tree

apps/web/src/components/ChatMarkdown.test.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,21 @@ describe("orderedListGutterStyle", () => {
2424
it("accounts for a non-default start attribute", () => {
2525
// start=95 + 9 items => last marker is "103", three digits.
2626
expect(orderedListGutterStyle(9, 95)).toEqual({ "--list-gutter": "4ch" });
27+
expect(orderedListGutterStyle(5, "999995")).toEqual({ "--list-gutter": "7ch" });
2728
});
2829

2930
it("scales further for four-digit markers", () => {
3031
expect(orderedListGutterStyle(1000, undefined)).toEqual({ "--list-gutter": "5ch" });
3132
});
3233

34+
it("uses the widest marker and includes a negative start's minus sign", () => {
35+
expect(orderedListGutterStyle(1001, -1000)).toEqual({ "--list-gutter": "6ch" });
36+
expect(orderedListGutterStyle(3, -15)).toEqual({ "--list-gutter": "4ch" });
37+
expect(orderedListGutterStyle(3, -5)).toBeUndefined();
38+
});
39+
3340
it("treats a missing/zero item count as a single item", () => {
3441
expect(orderedListGutterStyle(0, undefined)).toBeUndefined();
42+
expect(orderedListGutterStyle(0, 100)).toEqual({ "--list-gutter": "4ch" });
3543
});
3644
});

apps/web/src/components/ChatMarkdown.tsx

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -159,22 +159,24 @@ function findTaskListMarkerOffset(markdown: string, listItemStart: number): numb
159159
}
160160

161161
/**
162-
* The default `1.25rem` marker gutter (`.chat-markdown ol`) fits two-digit
163-
* decimal markers. Once a list's last item reaches three digits (item 100+),
164-
* `list-style-position: outside` paints the marker wider than that gutter and
165-
* the leading digit gets clipped by the item's own overflow. Rather than
166-
* widening the gutter for every list, only lists whose last marker is 3+
167-
* digits get a wider `--list-gutter`, sized to that marker's digit count.
162+
* The default `1.25rem` marker gutter (`.chat-markdown ol`) fits markers up to
163+
* two characters wide. Once a marker reaches three characters (item 100+),
164+
* `list-style-position: outside` paints it wider than that gutter and clips
165+
* the leading character against the item's own overflow. Rather than widening
166+
* the gutter for every list, only lists whose widest marker is 3+ characters
167+
* get a wider `--list-gutter`. The width includes a negative marker's minus
168+
* sign.
168169
*/
169170
export function orderedListGutterStyle(
170171
itemCount: number,
171-
start: number | undefined,
172+
start: unknown,
172173
): { "--list-gutter": string } | undefined {
173-
const firstNumber = typeof start === "number" && Number.isFinite(start) ? start : 1;
174+
const parsedStart = Number.parseInt(String(start ?? 1), 10);
175+
const firstNumber = Number.isNaN(parsedStart) ? 1 : parsedStart;
174176
const lastNumber = firstNumber + Math.max(itemCount - 1, 0);
175-
const digits = String(Math.abs(lastNumber)).length;
176-
if (digits <= 2) return undefined;
177-
return { "--list-gutter": `${digits + 1}ch` };
177+
const markerWidth = Math.max(String(firstNumber).length, String(lastNumber).length);
178+
if (markerWidth <= 2) return undefined;
179+
return { "--list-gutter": `${markerWidth + 1}ch` };
178180
}
179181

180182
const CHAT_MARKDOWN_SANITIZE_SCHEMA = {

apps/web/src/index.css

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,7 +2040,7 @@ code {
20402040

20412041
/* --list-gutter defaults to the same 1.25rem as .chat-markdown ul, but
20422042
ChatMarkdown's `ol` renderer widens it (via inline style) for lists whose
2043-
last marker is 3+ digits, so item 100+ isn't clipped by list-style-position:
2043+
widest marker is 3+ characters, so item 100+ isn't clipped by list-style-position:
20442044
outside painting the marker past the padding box. Reset it here too so a
20452045
nested ol without its own widened marker doesn't inherit the outer one. */
20462046
.chat-markdown ol {
@@ -2049,6 +2049,10 @@ code {
20492049
list-style-type: decimal;
20502050
}
20512051

2052+
.chat-markdown ol > li::marker {
2053+
font-variant-numeric: tabular-nums;
2054+
}
2055+
20522056
.chat-markdown ul ul {
20532057
list-style-type: circle;
20542058
}
@@ -2114,7 +2118,6 @@ code {
21142118

21152119
.chat-markdown section[data-footnotes] ol {
21162120
margin: 0;
2117-
padding-left: 1.25rem;
21182121
}
21192122

21202123
.chat-markdown section[data-footnotes] li + li {

0 commit comments

Comments
 (0)