[PM-5432] Overlay button iframe presents with a white background on websites that use dark mode (#7415)
* [PM-5432] Overlay button iframe presents with a white background * [PM-5432] Adding method that allows us to update the overlay button color scheme dynamically * [PM-5432] Adding jest tests to validate implementation changes
This commit is contained in:
parent
cc9a347482
commit
e3f20d81e2
|
@ -1,6 +1,6 @@
|
|||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
|
||||
type OverlayButtonMessage = { command: string };
|
||||
type OverlayButtonMessage = { command: string; colorScheme?: string };
|
||||
|
||||
type UpdateAuthStatusMessage = OverlayButtonMessage & { authStatus: AuthenticationStatus };
|
||||
|
||||
|
@ -18,10 +18,12 @@ type OverlayButtonWindowMessageHandlers = {
|
|||
}: {
|
||||
message: UpdateAuthStatusMessage;
|
||||
}) => void;
|
||||
updateOverlayPageColorScheme: ({ message }: { message: OverlayButtonMessage }) => void;
|
||||
};
|
||||
|
||||
export {
|
||||
UpdateAuthStatusMessage,
|
||||
OverlayButtonMessage,
|
||||
InitAutofillOverlayButtonMessage,
|
||||
OverlayButtonWindowMessageHandlers,
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@ type AutofillOverlayIframeExtensionMessage = {
|
|||
type AutofillOverlayIframeWindowMessageHandlers = {
|
||||
[key: string]: CallableFunction;
|
||||
updateAutofillOverlayListHeight: (message: AutofillOverlayIframeExtensionMessage) => void;
|
||||
getPageColorScheme: () => void;
|
||||
};
|
||||
|
||||
type AutofillOverlayIframeExtensionMessageParam = {
|
||||
|
|
|
@ -385,6 +385,46 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
expect(autofillOverlayIframeService["iframe"].style.height).toBe("300px");
|
||||
});
|
||||
|
||||
describe("getPageColorScheme window message", () => {
|
||||
afterEach(() => {
|
||||
globalThis.document.head.innerHTML = "";
|
||||
});
|
||||
|
||||
it("gets and updates the overlay page color scheme", () => {
|
||||
const colorSchemeMetaTag = globalThis.document.createElement("meta");
|
||||
colorSchemeMetaTag.setAttribute("name", "color-scheme");
|
||||
colorSchemeMetaTag.setAttribute("content", "dark");
|
||||
globalThis.document.head.append(colorSchemeMetaTag);
|
||||
globalThis.dispatchEvent(
|
||||
new MessageEvent("message", {
|
||||
data: { command: "getPageColorScheme" },
|
||||
source: autofillOverlayIframeService["iframe"].contentWindow,
|
||||
origin: "chrome-extension://id",
|
||||
}),
|
||||
);
|
||||
|
||||
expect(autofillOverlayIframeService["iframe"].contentWindow.postMessage).toBeCalledWith(
|
||||
{ command: "updateOverlayPageColorScheme", colorScheme: "dark" },
|
||||
"*",
|
||||
);
|
||||
});
|
||||
|
||||
it("sends a normal color scheme if the color scheme meta tag is not present", () => {
|
||||
globalThis.dispatchEvent(
|
||||
new MessageEvent("message", {
|
||||
data: { command: "getPageColorScheme" },
|
||||
source: autofillOverlayIframeService["iframe"].contentWindow,
|
||||
origin: "chrome-extension://id",
|
||||
}),
|
||||
);
|
||||
|
||||
expect(autofillOverlayIframeService["iframe"].contentWindow.postMessage).toBeCalledWith(
|
||||
{ command: "updateOverlayPageColorScheme", colorScheme: "normal" },
|
||||
"*",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
|
|||
private readonly windowMessageHandlers: AutofillOverlayIframeWindowMessageHandlers = {
|
||||
updateAutofillOverlayListHeight: (message) =>
|
||||
this.updateElementStyles(this.iframe, message.styles),
|
||||
getPageColorScheme: () => this.updateOverlayPageColorScheme(),
|
||||
};
|
||||
private readonly backgroundPortMessageHandlers: BackgroundPortMessageHandlers = {
|
||||
initAutofillOverlayList: ({ message }) => this.initAutofillOverlayList(message),
|
||||
|
@ -238,6 +239,22 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
|
|||
this.announceAriaAlert();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the page color scheme meta tag and sends a message to the iframe
|
||||
* to update its color scheme. Will default to "normal" if the meta tag
|
||||
* does not exist.
|
||||
*/
|
||||
private updateOverlayPageColorScheme() {
|
||||
const colorSchemeValue = globalThis.document
|
||||
.querySelector("meta[name='color-scheme']")
|
||||
?.getAttribute("content");
|
||||
|
||||
this.iframe.contentWindow?.postMessage(
|
||||
{ command: "updateOverlayPageColorScheme", colorScheme: colorSchemeValue || "normal" },
|
||||
"*",
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles messages sent from the iframe. If the message does not have a
|
||||
* specified handler set, it passes the message to the background script.
|
||||
|
|
|
@ -64,7 +64,9 @@ describe("AutofillOverlayButton", () => {
|
|||
|
||||
postWindowMessage({ command: "checkAutofillOverlayButtonFocused" });
|
||||
|
||||
expect(globalThis.parent.postMessage).not.toHaveBeenCalled();
|
||||
expect(globalThis.parent.postMessage).not.toHaveBeenCalledWith({
|
||||
command: "closeAutofillOverlay",
|
||||
});
|
||||
});
|
||||
|
||||
it("posts a message to close the autofill overlay if the element is not focused during the focus check", () => {
|
||||
|
@ -88,5 +90,19 @@ describe("AutofillOverlayButton", () => {
|
|||
|
||||
expect(autofillOverlayButton["authStatus"]).toBe(AuthenticationStatus.Unlocked);
|
||||
});
|
||||
|
||||
it("updates the page color scheme meta tag", () => {
|
||||
const colorSchemeMetaTag = globalThis.document.createElement("meta");
|
||||
colorSchemeMetaTag.setAttribute("name", "color-scheme");
|
||||
colorSchemeMetaTag.setAttribute("content", "light");
|
||||
globalThis.document.head.append(colorSchemeMetaTag);
|
||||
|
||||
postWindowMessage({
|
||||
command: "updateOverlayPageColorScheme",
|
||||
colorScheme: "dark",
|
||||
});
|
||||
|
||||
expect(colorSchemeMetaTag.getAttribute("content")).toBe("dark");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@ import { buildSvgDomElement } from "../../../utils";
|
|||
import { logoIcon, logoLockedIcon } from "../../../utils/svg-icons";
|
||||
import {
|
||||
InitAutofillOverlayButtonMessage,
|
||||
OverlayButtonMessage,
|
||||
OverlayButtonWindowMessageHandlers,
|
||||
} from "../../abstractions/autofill-overlay-button";
|
||||
import AutofillOverlayPageElement from "../shared/autofill-overlay-page-element";
|
||||
|
@ -21,6 +22,7 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||
checkAutofillOverlayButtonFocused: () => this.checkButtonFocused(),
|
||||
updateAutofillOverlayButtonAuthStatus: ({ message }) =>
|
||||
this.updateAuthStatus(message.authStatus),
|
||||
updateOverlayPageColorScheme: ({ message }) => this.updatePageColorScheme(message),
|
||||
};
|
||||
|
||||
constructor() {
|
||||
|
@ -61,6 +63,7 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||
this.getTranslation("toggleBitwardenVaultOverlay"),
|
||||
);
|
||||
this.buttonElement.addEventListener(EVENTS.CLICK, this.handleButtonElementClick);
|
||||
this.postMessageToParent({ command: "getPageColorScheme" });
|
||||
|
||||
this.updateAuthStatus(authStatus);
|
||||
|
||||
|
@ -84,6 +87,17 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||
this.buttonElement.append(iconElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles updating the page color scheme meta tag. Ensures that the button
|
||||
* does not present with a non-transparent background on dark mode pages.
|
||||
*
|
||||
* @param colorScheme - The color scheme of the iframe's parent page
|
||||
*/
|
||||
private updatePageColorScheme({ colorScheme }: OverlayButtonMessage) {
|
||||
const colorSchemeMetaTag = globalThis.document.querySelector("meta[name='color-scheme']");
|
||||
colorSchemeMetaTag?.setAttribute("content", colorScheme);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a click event on the button element. Posts a message to the
|
||||
* parent window indicating that the button was clicked.
|
||||
|
|
Loading…
Reference in New Issue