Make document highlights opaque yellow

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-05-26 12:09:54 +00:00
1 parent d40e3fcae9
commit 54568231e7
2 files changed
+103 -4

No files matched your search

@@ -0,0 +1,99 @@
// @vitest-environment jsdom
import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { DocumentAnnotationLayer } from "./DocumentAnnotationLayer";
const mockRangesForNormalizedSpan = vi.hoisted(() => vi.fn());
vi.mock("@/lib/document-annotation-selection", () => ({
buildAnchorFromContainerSelection: vi.fn(),
getContainerTextOffset: vi.fn(),
rangesForNormalizedSpan: mockRangesForNormalizedSpan,
}));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;
function makeRect(left: number, top: number, width: number, height: number): DOMRect {
return {
x: left,
y: top,
left,
top,
right: left + width,
bottom: top + height,
width,
height,
toJSON: () => ({}),
} as DOMRect;
}
describe("DocumentAnnotationLayer", () => {
let container: HTMLDivElement;
let rectSpy: ReturnType<typeof vi.spyOn>;
let root: Root | null = null;
beforeEach(() => {
container = document.createElement("div");
document.body.appendChild(container);
mockRangesForNormalizedSpan.mockReturnValue([
{
getClientRects: () => [makeRect(8, 12, 80, 18)],
},
]);
rectSpy = vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockReturnValue(makeRect(0, 0, 400, 300));
});
afterEach(() => {
if (root) {
act(() => root?.unmount());
root = null;
}
rectSpy.mockRestore();
container.remove();
vi.clearAllMocks();
});
it("uses solid yellow backgrounds for annotation highlights in light and dark themes", async () => {
const body = document.createElement("div");
body.textContent = "Annotated body text.";
root = createRoot(container);
await act(async () => {
root?.render(
<DocumentAnnotationLayer
containerRef={{ current: body }}
markdown="Annotated body text."
threads={[
{ id: "active", selectedText: "Annotated", status: "open", anchorState: "active" },
{ id: "focused", selectedText: "body", status: "open", anchorState: "active" },
{ id: "stale", selectedText: "text", status: "open", anchorState: "stale" },
{ id: "resolved", selectedText: "body text", status: "resolved", anchorState: "active" },
]}
focusedThreadId="focused"
onThreadFocus={vi.fn()}
pendingAnchor={null}
onPendingAnchorChange={vi.fn()}
onRequestComment={vi.fn()}
hideResolved={false}
/>,
);
await new Promise((resolve) => window.requestAnimationFrame(resolve));
});
const highlights = Array.from(container.querySelectorAll(".paperclip-doc-annotation-highlight"));
expect(highlights).toHaveLength(4);
for (const highlight of highlights) {
const backgroundClasses = Array.from(highlight.classList).filter((className) =>
/^(dark:|hover:|dark:hover:)?bg-yellow-\d+$/.test(className)
|| /^(dark:|hover:|dark:hover:)?bg-yellow-\d+\//.test(className),
);
expect(backgroundClasses.some((className) => className.includes("/"))).toBe(false);
expect(backgroundClasses.some((className) => className.startsWith("bg-yellow-"))).toBe(true);
expect(backgroundClasses.some((className) => className.startsWith("dark:bg-yellow-"))).toBe(true);
}
});
});
@@ -268,12 +268,12 @@ export function DocumentAnnotationLayer({
"paperclip-doc-annotation-highlight pointer-events-auto absolute cursor-pointer rounded-none transition-colors",
// base box treatment (replaces the previous baseline border)
isResolved
? "bg-yellow-300/25 outline outline-1 outline-dashed outline-offset-0 outline-yellow-700/45 hover:bg-yellow-300/35 dark:bg-yellow-300/18 dark:outline-yellow-200/45"
? "bg-yellow-100 outline outline-1 outline-dashed outline-offset-0 outline-yellow-700/45 hover:bg-yellow-200 dark:bg-yellow-700 dark:outline-yellow-200/45 dark:hover:bg-yellow-600"
: isStale
? "bg-yellow-300/35 outline outline-2 outline-dashed outline-offset-0 outline-yellow-700/65 hover:bg-yellow-300/45 dark:bg-yellow-300/24 dark:outline-yellow-200/70"
? "bg-yellow-200 outline outline-2 outline-dashed outline-offset-0 outline-yellow-700/65 hover:bg-yellow-300 dark:bg-yellow-600 dark:outline-yellow-200/70 dark:hover:bg-yellow-500"
: isFocused
? "bg-yellow-300/55 outline outline-2 outline-offset-0 outline-yellow-700/85 shadow-[0_0_0_1px_var(--color-background)] dark:bg-yellow-300/35 dark:outline-yellow-200/85"
: "bg-yellow-300/40 hover:bg-yellow-300/55 dark:bg-yellow-300/24 dark:hover:bg-yellow-300/34",
? "bg-yellow-300 outline outline-2 outline-offset-0 outline-yellow-700/85 shadow-[0_0_0_1px_var(--color-background)] hover:bg-yellow-300 dark:bg-yellow-500 dark:outline-yellow-200/85 dark:hover:bg-yellow-400"
: "bg-yellow-200 hover:bg-yellow-300 dark:bg-yellow-600 dark:hover:bg-yellow-500",
)}
style={{
top: rect.top,