mirror of
https://github.com/bitwarden/browser.git
synced 2025-03-11 13:30:39 +01:00
[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";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
|
|
||||||
type OverlayButtonMessage = { command: string };
|
type OverlayButtonMessage = { command: string; colorScheme?: string };
|
||||||
|
|
||||||
type UpdateAuthStatusMessage = OverlayButtonMessage & { authStatus: AuthenticationStatus };
|
type UpdateAuthStatusMessage = OverlayButtonMessage & { authStatus: AuthenticationStatus };
|
||||||
|
|
||||||
@ -18,10 +18,12 @@ type OverlayButtonWindowMessageHandlers = {
|
|||||||
}: {
|
}: {
|
||||||
message: UpdateAuthStatusMessage;
|
message: UpdateAuthStatusMessage;
|
||||||
}) => void;
|
}) => void;
|
||||||
|
updateOverlayPageColorScheme: ({ message }: { message: OverlayButtonMessage }) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
UpdateAuthStatusMessage,
|
UpdateAuthStatusMessage,
|
||||||
|
OverlayButtonMessage,
|
||||||
InitAutofillOverlayButtonMessage,
|
InitAutofillOverlayButtonMessage,
|
||||||
OverlayButtonWindowMessageHandlers,
|
OverlayButtonWindowMessageHandlers,
|
||||||
};
|
};
|
||||||
|
@ -7,6 +7,7 @@ type AutofillOverlayIframeExtensionMessage = {
|
|||||||
type AutofillOverlayIframeWindowMessageHandlers = {
|
type AutofillOverlayIframeWindowMessageHandlers = {
|
||||||
[key: string]: CallableFunction;
|
[key: string]: CallableFunction;
|
||||||
updateAutofillOverlayListHeight: (message: AutofillOverlayIframeExtensionMessage) => void;
|
updateAutofillOverlayListHeight: (message: AutofillOverlayIframeExtensionMessage) => void;
|
||||||
|
getPageColorScheme: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type AutofillOverlayIframeExtensionMessageParam = {
|
type AutofillOverlayIframeExtensionMessageParam = {
|
||||||
|
@ -385,6 +385,46 @@ describe("AutofillOverlayIframeService", () => {
|
|||||||
|
|
||||||
expect(autofillOverlayIframeService["iframe"].style.height).toBe("300px");
|
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 = {
|
private readonly windowMessageHandlers: AutofillOverlayIframeWindowMessageHandlers = {
|
||||||
updateAutofillOverlayListHeight: (message) =>
|
updateAutofillOverlayListHeight: (message) =>
|
||||||
this.updateElementStyles(this.iframe, message.styles),
|
this.updateElementStyles(this.iframe, message.styles),
|
||||||
|
getPageColorScheme: () => this.updateOverlayPageColorScheme(),
|
||||||
};
|
};
|
||||||
private readonly backgroundPortMessageHandlers: BackgroundPortMessageHandlers = {
|
private readonly backgroundPortMessageHandlers: BackgroundPortMessageHandlers = {
|
||||||
initAutofillOverlayList: ({ message }) => this.initAutofillOverlayList(message),
|
initAutofillOverlayList: ({ message }) => this.initAutofillOverlayList(message),
|
||||||
@ -238,6 +239,22 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
|
|||||||
this.announceAriaAlert();
|
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
|
* Handles messages sent from the iframe. If the message does not have a
|
||||||
* specified handler set, it passes the message to the background script.
|
* specified handler set, it passes the message to the background script.
|
||||||
|
@ -64,7 +64,9 @@ describe("AutofillOverlayButton", () => {
|
|||||||
|
|
||||||
postWindowMessage({ command: "checkAutofillOverlayButtonFocused" });
|
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", () => {
|
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);
|
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 { logoIcon, logoLockedIcon } from "../../../utils/svg-icons";
|
||||||
import {
|
import {
|
||||||
InitAutofillOverlayButtonMessage,
|
InitAutofillOverlayButtonMessage,
|
||||||
|
OverlayButtonMessage,
|
||||||
OverlayButtonWindowMessageHandlers,
|
OverlayButtonWindowMessageHandlers,
|
||||||
} from "../../abstractions/autofill-overlay-button";
|
} from "../../abstractions/autofill-overlay-button";
|
||||||
import AutofillOverlayPageElement from "../shared/autofill-overlay-page-element";
|
import AutofillOverlayPageElement from "../shared/autofill-overlay-page-element";
|
||||||
@ -21,6 +22,7 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||||||
checkAutofillOverlayButtonFocused: () => this.checkButtonFocused(),
|
checkAutofillOverlayButtonFocused: () => this.checkButtonFocused(),
|
||||||
updateAutofillOverlayButtonAuthStatus: ({ message }) =>
|
updateAutofillOverlayButtonAuthStatus: ({ message }) =>
|
||||||
this.updateAuthStatus(message.authStatus),
|
this.updateAuthStatus(message.authStatus),
|
||||||
|
updateOverlayPageColorScheme: ({ message }) => this.updatePageColorScheme(message),
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -61,6 +63,7 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||||||
this.getTranslation("toggleBitwardenVaultOverlay"),
|
this.getTranslation("toggleBitwardenVaultOverlay"),
|
||||||
);
|
);
|
||||||
this.buttonElement.addEventListener(EVENTS.CLICK, this.handleButtonElementClick);
|
this.buttonElement.addEventListener(EVENTS.CLICK, this.handleButtonElementClick);
|
||||||
|
this.postMessageToParent({ command: "getPageColorScheme" });
|
||||||
|
|
||||||
this.updateAuthStatus(authStatus);
|
this.updateAuthStatus(authStatus);
|
||||||
|
|
||||||
@ -84,6 +87,17 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||||||
this.buttonElement.append(iconElement);
|
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
|
* Handles a click event on the button element. Posts a message to the
|
||||||
* parent window indicating that the button was clicked.
|
* parent window indicating that the button was clicked.
|
||||||
|
Loading…
Reference in New Issue
Block a user