Skip to content

Commit 48dc069

Browse files
committed
fix(mdviewer): checkbox styling, format bar in code blocks, cursor fixes
- Fix task list checkbox styling: use li:has(> input[checkbox]) instead of missing task-list-item class (marked v17 doesn't add it) - Hide bullet points on task list items, add min-height for empty items - Hide format bar when selection is inside code blocks - Prevent cursor from being placed before checkbox in task list items - Backspace after checkbox removes it, converting to regular bullet
1 parent e10123b commit 48dc069

2 files changed

Lines changed: 65 additions & 7 deletions

File tree

src-mdviewer/src/components/editor.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2099,6 +2099,32 @@ function enterEditMode(content) {
20992099
return;
21002100
}
21012101

2102+
// Backspace right after a checkbox → remove the checkbox
2103+
if (e.key === "Backspace" && !mod) {
2104+
const sel2 = window.getSelection();
2105+
if (sel2 && sel2.isCollapsed && sel2.rangeCount) {
2106+
const range2 = sel2.getRangeAt(0);
2107+
const li = (range2.startContainer.nodeType === Node.TEXT_NODE
2108+
? range2.startContainer.parentElement : range2.startContainer)?.closest("li");
2109+
if (li) {
2110+
const cb = li.querySelector('input[type="checkbox"]');
2111+
if (cb) {
2112+
// Check if cursor is right after the checkbox
2113+
const cbIdx = Array.from(li.childNodes).indexOf(cb);
2114+
const isAfterCb = (range2.startContainer === li && range2.startOffset === cbIdx + 1) ||
2115+
(range2.startContainer.nodeType === Node.TEXT_NODE &&
2116+
range2.startOffset === 0 && range2.startContainer.previousSibling === cb);
2117+
if (isAfterCb) {
2118+
e.preventDefault();
2119+
cb.remove();
2120+
content.dispatchEvent(new Event("input", { bubbles: true }));
2121+
return;
2122+
}
2123+
}
2124+
}
2125+
}
2126+
}
2127+
21022128
// Backspace at start of heading → convert to paragraph
21032129
if (e.key === "Backspace" && !mod) {
21042130
const sel2 = window.getSelection();
@@ -2340,7 +2366,31 @@ function enterEditMode(content) {
23402366
};
23412367
content.addEventListener("keydown", keydownHandler);
23422368

2343-
selectionHandler = () => broadcastSelectionState();
2369+
selectionHandler = () => {
2370+
// Prevent cursor from being placed before a checkbox in task list items.
2371+
// In contenteditable, the caret can land at offset 0 in an <li> before
2372+
// the <input>, which looks wrong (cursor appears before the bullet).
2373+
const sel = window.getSelection();
2374+
if (sel && sel.isCollapsed && sel.anchorNode) {
2375+
const li = sel.anchorNode.nodeType === Node.ELEMENT_NODE
2376+
? sel.anchorNode.closest("li")
2377+
: sel.anchorNode.parentElement?.closest("li");
2378+
if (li) {
2379+
const cb = li.querySelector('input[type="checkbox"]');
2380+
if (cb && (sel.anchorNode === li && sel.anchorOffset === 0 ||
2381+
sel.anchorNode === cb || cb.contains(sel.anchorNode))) {
2382+
const r = document.createRange();
2383+
// Place cursor right after the checkbox
2384+
const cbIdx = Array.from(li.childNodes).indexOf(cb);
2385+
r.setStart(li, cbIdx + 1);
2386+
r.collapse(true);
2387+
sel.removeAllRanges();
2388+
sel.addRange(r);
2389+
}
2390+
}
2391+
}
2392+
broadcastSelectionState();
2393+
};
23442394
document.addEventListener("selectionchange", selectionHandler);
23452395
selectionFallbackMouseUp = () => broadcastSelectionState();
23462396
selectionFallbackKeyUp = () => broadcastSelectionState();

src-mdviewer/src/styles/markdown.css

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,24 +313,32 @@
313313
}
314314

315315
/* Task lists */
316-
.markdown-body .contains-task-list {
316+
/* Task list: target li elements that contain a checkbox directly,
317+
since marked v17 does not add task-list-item/contains-task-list classes. */
318+
.markdown-body li:has(> input[type="checkbox"]) {
317319
list-style: none;
318-
padding-inline-start: 0;
319-
}
320-
321-
.markdown-body .task-list-item {
322320
position: relative;
323321
padding-inline-start: 1.75em;
322+
margin-inline-start: -1.75em;
323+
min-height: 1.5em;
324324
}
325325

326-
.markdown-body .task-list-item input[type="checkbox"] {
326+
.markdown-body li > input[type="checkbox"] {
327327
position: absolute;
328328
inset-inline-start: 0;
329329
top: 0.3em;
330330
width: 1em;
331331
height: 1em;
332+
margin: 0;
332333
accent-color: var(--color-accent);
333334
pointer-events: none;
335+
cursor: default;
336+
}
337+
338+
/* In edit mode, checkboxes are enabled */
339+
.markdown-body li > input[type="checkbox"]:not([disabled]) {
340+
pointer-events: auto;
341+
cursor: pointer;
334342
}
335343

336344
/* Horizontal rule */

0 commit comments

Comments
 (0)