Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/chrome-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@types/react-dom": "19.2.3",
"@vitejs/plugin-react": "4.4.1",
"autoprefixer": "^10.4.16",
"jsdom": "^26.1.0",
"postcss": "^8.4.31",
"tailwindcss": "^3.4.0",
"typescript": "^5.8.3",
Expand Down
125 changes: 125 additions & 0 deletions apps/chrome-extension/src/content/blur-overlay.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// @vitest-environment jsdom
Comment thread
vedanth-jadhav marked this conversation as resolved.

import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { BlurOverlay } from "./blur-overlay";

let root: Root;
let host: HTMLDivElement;
let target: HTMLDivElement;
const onDone = vi.fn();

beforeEach(() => {
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
host = document.createElement("div");
target = document.createElement("div");
document.body.append(host, target);
Object.defineProperty(document, "elementFromPoint", {
configurable: true,
value: vi.fn(() => target),
});
root = createRoot(host);
act(() => root.render(<BlurOverlay active onDone={onDone} />));
});

afterEach(() => {
act(() => root.unmount());
host.remove();
target.remove();
Reflect.deleteProperty(document, "elementFromPoint");
vi.unstubAllGlobals();
});

const clickTarget = () => {
const event = new MouseEvent("click", { bubbles: true, cancelable: true });
act(() => target.dispatchEvent(event));
return event;
};

describe("blur style restoration", () => {
it.each([
{
filter: "contrast(2)",
filterPriority: "important",
select: "text",
selectPriority: "important",
},
{
filter: "grayscale(1)",
filterPriority: "",
select: "all",
selectPriority: "",
},
{
filter: "",
filterPriority: "",
select: "none",
selectPriority: "important",
},
])(
"restores the original inline values and priorities: $select/$filter",
(styles) => {
target.style.setProperty("filter", styles.filter, styles.filterPriority);
target.style.setProperty(
"user-select",
styles.select,
styles.selectPriority,
);
target.style.setProperty("color", "red", "important");
for (let cycle = 0; cycle < 2; cycle++) {
expect(clickTarget().defaultPrevented).toBe(true);
expect(target.style.getPropertyValue("filter")).toBe("blur(12px)");
expect(target.style.getPropertyPriority("filter")).toBe("important");
expect(target.style.getPropertyValue("user-select")).toBe("none");
expect(target.style.getPropertyPriority("user-select")).toBe(
"important",
);
clickTarget();
expect(target.style.getPropertyValue("filter")).toBe(styles.filter);
expect(target.style.getPropertyPriority("filter")).toBe(
styles.filterPriority,
);
expect(target.style.getPropertyValue("user-select")).toBe(
styles.select,
);
expect(target.style.getPropertyPriority("user-select")).toBe(
styles.selectPriority,
);
expect(target.style.getPropertyValue("color")).toBe("red");
expect(target.style.getPropertyPriority("color")).toBe("important");
expect(Object.keys(target.dataset)).toEqual([]);
}
},
);

it("removes temporary styles when the target had no inline declarations", () => {
clickTarget();
clickTarget();
expect(target.style.getPropertyValue("filter")).toBe("");
expect(target.style.getPropertyValue("user-select")).toBe("");
expect(Object.keys(target.dataset)).toEqual([]);
});

it("retains saved styles when the blur tool closes and reopens", () => {
target.style.setProperty("user-select", "text", "important");
clickTarget();
act(() => root.render(<BlurOverlay active={false} onDone={onDone} />));
expect(clickTarget().defaultPrevented).toBe(false);
expect(target.style.getPropertyValue("filter")).toBe("blur(12px)");
act(() => root.render(<BlurOverlay active onDone={onDone} />));
clickTarget();
expect(target.style.getPropertyValue("user-select")).toBe("text");
expect(target.style.getPropertyPriority("user-select")).toBe("important");
expect(Object.keys(target.dataset)).toEqual([]);
});

it("ignores extension controls", () => {
target.id = "cap-extension-recorder-overlay";
target.style.setProperty("user-select", "text", "important");
expect(clickTarget().defaultPrevented).toBe(false);
expect(target.style.getPropertyValue("user-select")).toBe("text");
expect(target.style.getPropertyPriority("user-select")).toBe("important");
expect(Object.keys(target.dataset)).toEqual([]);
});
});
26 changes: 24 additions & 2 deletions apps/chrome-extension/src/content/blur-overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,37 @@ export function BlurOverlay({ active, onDone }: BlurOverlayProps) {
if (target.dataset.capBlurred === "true") {
const orig = target.dataset.capOrigFilter ?? "";
if (orig) {
target.style.filter = orig;
target.style.setProperty(
"filter",
orig,
target.dataset.capOrigFilterPriority ?? "",
);
} else {
target.style.removeProperty("filter");
}
target.style.removeProperty("user-select");
const originalSelection = target.dataset.capOrigUserSelect ?? "";
if (originalSelection) {
target.style.setProperty(
"user-select",
originalSelection,
target.dataset.capOrigUserSelectPriority ?? "",
);
} else {
target.style.removeProperty("user-select");
}
delete target.dataset.capBlurred;
delete target.dataset.capOrigFilter;
delete target.dataset.capOrigFilterPriority;
delete target.dataset.capOrigUserSelect;
delete target.dataset.capOrigUserSelectPriority;
} else {
target.dataset.capOrigFilter = target.style.filter || "";
target.dataset.capOrigFilterPriority =
target.style.getPropertyPriority("filter");
target.dataset.capOrigUserSelect =
target.style.getPropertyValue("user-select");
target.dataset.capOrigUserSelectPriority =
target.style.getPropertyPriority("user-select");
target.style.setProperty("filter", "blur(12px)", "important");
target.style.setProperty("user-select", "none", "important");
target.dataset.capBlurred = "true";
Expand Down
Loading
Loading