mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
fix(ui): neutralize password manager autofill highlight on auth inputs
This commit is contained in:
@@ -16,6 +16,7 @@ import { Button } from "@/components/shadcn";
|
||||
import { useToast } from "@/components/shadcn";
|
||||
import { CustomInput } from "@/components/shadcn/custom";
|
||||
import { Form } from "@/components/shadcn/form";
|
||||
import { stripPasswordManagerHighlight } from "@/lib/password-manager";
|
||||
import { SignInFormData, signInSchema } from "@/types";
|
||||
|
||||
export const SignInForm = ({
|
||||
@@ -146,6 +147,7 @@ export const SignInForm = ({
|
||||
<AuthLayout title={title}>
|
||||
<Form {...form}>
|
||||
<form
|
||||
ref={stripPasswordManagerHighlight}
|
||||
noValidate
|
||||
method="post"
|
||||
className="flex flex-col gap-4"
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
FormField,
|
||||
FormMessage,
|
||||
} from "@/components/shadcn/form";
|
||||
import { stripPasswordManagerHighlight } from "@/lib/password-manager";
|
||||
import { ApiError, SignUpFormData, signUpSchema } from "@/types";
|
||||
|
||||
const AUTH_ERROR_PATHS = {
|
||||
@@ -152,6 +153,7 @@ export const SignUpForm = ({
|
||||
<AuthLayout title="Sign up">
|
||||
<Form {...form}>
|
||||
<form
|
||||
ref={stripPasswordManagerHighlight}
|
||||
noValidate
|
||||
method="post"
|
||||
className="flex flex-col gap-4"
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// 1Password marks autofilled fields with data-com-onepassword-filled and paints
|
||||
// a "filled" background highlight via styles injected outside the author cascade
|
||||
// (web component / adopted sheet), so CSS overrides can't win. Removing the
|
||||
// attribute makes its selector stop matching, restoring the design styles while
|
||||
// leaving autofill itself untouched.
|
||||
const ONEPASSWORD_FILLED_ATTR = "data-com-onepassword-filled";
|
||||
|
||||
/**
|
||||
* Ref callback for a form (or any container) that strips password-manager
|
||||
* fill highlights from descendant inputs.
|
||||
*
|
||||
* Returns a cleanup function so it works as a React 19 ref-callback cleanup —
|
||||
* no useEffect needed. Cheap by design: the observer is scoped to the container
|
||||
* and filtered to a single attribute, so the browser only invokes it when the
|
||||
* password manager toggles that attribute (once per fill), never per frame.
|
||||
*
|
||||
* @example
|
||||
* <form ref={stripPasswordManagerHighlight}>…</form>
|
||||
*/
|
||||
export const stripPasswordManagerHighlight = (
|
||||
container: HTMLElement | null,
|
||||
): (() => void) | void => {
|
||||
if (!container) return;
|
||||
|
||||
// removeAttribute on an element without the attribute is a no-op and emits no
|
||||
// mutation record, so re-firing the observer on our own removal can't loop.
|
||||
const strip = (element: Element) =>
|
||||
element.removeAttribute(ONEPASSWORD_FILLED_ATTR);
|
||||
|
||||
container.querySelectorAll(`[${ONEPASSWORD_FILLED_ATTR}]`).forEach(strip);
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
for (const { target } of mutations) {
|
||||
if (target instanceof Element) strip(target);
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(container, {
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
attributeFilter: [ONEPASSWORD_FILLED_ATTR],
|
||||
});
|
||||
|
||||
return () => observer.disconnect();
|
||||
};
|
||||
@@ -476,6 +476,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Neutralize the browser's native autofill highlight (Chromium/WebKit paint a
|
||||
forced blue/yellow background on :autofill). box-shadow inset masks it; the
|
||||
long transition stops the native color from flashing before the mask lands.
|
||||
Kept UNLAYERED + !important: the mask is a box-shadow and collides with
|
||||
shadcn's focus:ring (also a box-shadow, in @layer utilities) — a layered
|
||||
rule can't win that, so this sits outside the cascade layers. */
|
||||
input:autofill,
|
||||
input:autofill:hover,
|
||||
input:autofill:focus,
|
||||
input:autofill:active,
|
||||
input:-webkit-autofill,
|
||||
input:-webkit-autofill:hover,
|
||||
input:-webkit-autofill:focus,
|
||||
input:-webkit-autofill:active {
|
||||
-webkit-text-fill-color: var(--text-neutral-secondary) !important;
|
||||
-webkit-box-shadow: 0 0 0 1000px var(--bg-input-primary) inset !important;
|
||||
box-shadow: 0 0 0 1000px var(--bg-input-primary) inset !important;
|
||||
caret-color: var(--text-neutral-secondary);
|
||||
transition: background-color 5000s ease-in-out 0s;
|
||||
}
|
||||
|
||||
/* Override vaul's injected user-select: none to allow text selection in drawers */
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
[data-vaul-drawer][data-vaul-drawer] {
|
||||
|
||||
Reference in New Issue
Block a user