diff --git a/src/features/vcs/__tests__/diffOptions.test.ts b/src/features/vcs/__tests__/diffOptions.test.ts index 40b337d50..f3066b6e9 100644 --- a/src/features/vcs/__tests__/diffOptions.test.ts +++ b/src/features/vcs/__tests__/diffOptions.test.ts @@ -186,6 +186,22 @@ describe("diff options", () => { parent.remove(); }); + it("gives a read-only side a tab stop and leaves an editable side alone", () => { + const parent = document.createElement("div"); + document.body.appendChild(parent); + const mv = new MergeView({ + a: { doc: "old\n", extensions: viewerBase({ readOnly: true }) }, + b: { doc: "new\n", extensions: viewerBase({ readOnly: false }) }, + parent, + }); + expect(mv.a.contentDOM.getAttribute("contenteditable")).toBe("false"); + expect(mv.a.contentDOM.getAttribute("tabindex")).toBe("0"); + expect(mv.b.contentDOM.getAttribute("contenteditable")).toBe("true"); + expect(mv.b.contentDOM.hasAttribute("tabindex")).toBe(false); + mv.destroy(); + parent.remove(); + }); + it("transfers a chunk between sides (>> / << / Revert)", () => { const a = doc("x\nold\ny\n"); const b = doc("x\nnew\nnewer\ny\n"); diff --git a/src/features/vcs/cm.ts b/src/features/vcs/cm.ts index 8e4dd3272..e1e912113 100644 --- a/src/features/vcs/cm.ts +++ b/src/features/vcs/cm.ts @@ -100,9 +100,9 @@ export const viewerTheme = EditorView.theme( fontSize: "var(--fs-code)", }, ".cm-scroller": { fontFamily: "var(--font-mono)", fontWeight: "var(--fw-code, 400)", lineHeight: "var(--lh-code)" }, - ".cm-content": { caretColor: "var(--accent)" }, + ".cm-content": { caretColor: "var(--accent)", WebkitUserSelect: "text", userSelect: "text" }, ".cm-cursor, .cm-dropCursor": { borderLeftColor: "var(--accent)" }, - "&.cm-focused .cm-selectionBackground, .cm-selectionBackground, ::selection": { + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, ::selection": { backgroundColor: "var(--bg-selected-strong)", }, ".cm-activeLine": { backgroundColor: "var(--bg-current-line)" }, @@ -180,6 +180,8 @@ export function viewerBase(opts: { readOnly: boolean; lineNumbers?: boolean }): wholeChangedLines, EditorState.readOnly.of(opts.readOnly), EditorView.editable.of(!opts.readOnly), + // Non-editable revision panes still need keyboard selection and copy. + opts.readOnly ? EditorView.contentAttributes.of({ tabindex: "0" }) : [], ]; }