From f6763ff259265f13325a04b3f2804a2f85378038 Mon Sep 17 00:00:00 2001
From: Cee Chen <549407+cee-chen@users.noreply.github.com>
Date: Tue, 21 May 2024 10:45:29 -0700
Subject: [PATCH] Update form autofill colors on webkit browsers (#7776)

---
 packages/eui/changelogs/upcoming/7776.md      |  3 ++
 .../form/field_text/field_text.stories.tsx    | 22 +++++++++
 .../form/field_text/field_text.styles.ts      |  4 +-
 .../src/components/form/form.styles.test.tsx  | 15 +++---
 .../eui/src/components/form/form.styles.ts    | 49 ++++++++++++++-----
 5 files changed, 73 insertions(+), 20 deletions(-)
 create mode 100644 packages/eui/changelogs/upcoming/7776.md

diff --git a/packages/eui/changelogs/upcoming/7776.md b/packages/eui/changelogs/upcoming/7776.md
new file mode 100644
index 00000000000..ceaeea60bd3
--- /dev/null
+++ b/packages/eui/changelogs/upcoming/7776.md
@@ -0,0 +1,3 @@
+**CSS-in-JS conversions**
+
+- Updated the autofill colors of Chrome (and other webkit browsers) to better match EUI's light and dark mode
diff --git a/packages/eui/src/components/form/field_text/field_text.stories.tsx b/packages/eui/src/components/form/field_text/field_text.stories.tsx
index 4484f691814..1c4276c974d 100644
--- a/packages/eui/src/components/form/field_text/field_text.stories.tsx
+++ b/packages/eui/src/components/form/field_text/field_text.stories.tsx
@@ -6,6 +6,7 @@
  * Side Public License, v 1.
  */
 
+import React from 'react';
 import type { Meta, StoryObj } from '@storybook/react';
 import {
   disableStorybookControls,
@@ -62,3 +63,24 @@ moveStorybookControlsToCategory(IconShape, [
 ]);
 // Hide props that remove or won't affect the icon or its positioning
 hideStorybookControls(IconShape, ['controlOnly', 'inputRef']);
+
+export const AutoFill: Story = {
+  parameters: {
+    controls: { include: ['name', 'isInvalid'] },
+    loki: { skip: true },
+  },
+  decorators: [
+    (Story) => (
+      <form action="#">
+        In Chrome: Type any text, press Enter, then go back and select the
+        autofill suggestion. Test light+dark mode as well as invalid state
+        <br />
+        <br />
+        <Story />
+      </form>
+    ),
+  ],
+  args: {
+    name: 'autofill-test',
+  },
+};
diff --git a/packages/eui/src/components/form/field_text/field_text.styles.ts b/packages/eui/src/components/form/field_text/field_text.styles.ts
index 08a6d0a5894..dd1b194e8ca 100644
--- a/packages/eui/src/components/form/field_text/field_text.styles.ts
+++ b/packages/eui/src/components/form/field_text/field_text.styles.ts
@@ -34,7 +34,9 @@ export const euiFieldTextStyles = (euiThemeContext: UseEuiTheme) => {
         ${formStyles.readOnly}
       }
 
-      ${formStyles.autoFill}
+      &:autofill {
+        ${formStyles.autoFill}
+      }
     `,
 
     // Skip the css() on the default height to avoid generating a className
diff --git a/packages/eui/src/components/form/form.styles.test.tsx b/packages/eui/src/components/form/form.styles.test.tsx
index d65acf01cfe..80ff5357c83 100644
--- a/packages/eui/src/components/form/form.styles.test.tsx
+++ b/packages/eui/src/components/form/form.styles.test.tsx
@@ -31,7 +31,6 @@ describe('euiFormVariables', () => {
         "backgroundDisabledColor": "#eef1f7",
         "backgroundReadOnlyColor": "#FFF",
         "borderColor": "rgba(32,38,47,0.1)",
-        "controlAutoFillColor": "#343741",
         "controlBorderRadius": "6px",
         "controlBoxShadow": "0 0 transparent",
         "controlCompressedBorderRadius": "4px",
@@ -82,13 +81,15 @@ describe('euiFormControlStyles', () => {
     expect(result.current).toMatchInlineSnapshot(`
       Object {
         "autoFill": "
-            &:-webkit-autofill {
-              -webkit-text-fill-color: #343741;
+          &:-webkit-autofill {
+            -webkit-text-fill-color: #343741;
+            -webkit-box-shadow: inset 0 0 0 1px rgba(0,107,184,0.2), inset 0 0 0 100vw #f0f7fc;
 
-              ~ .euiFormControlLayoutIcons {
-                color: #343741;
-              }
-            }",
+            &:invalid {
+              -webkit-box-shadow: inset 0 0 0 1px #BD271E, inset 0 0 0 100vw #f0f7fc;
+            }
+          }
+        ",
         "compressed": "
             block-size: 32px;
             padding-block: 8px;
diff --git a/packages/eui/src/components/form/form.styles.ts b/packages/eui/src/components/form/form.styles.ts
index 3932e2ebfa0..d47b4940fcc 100644
--- a/packages/eui/src/components/form/form.styles.ts
+++ b/packages/eui/src/components/form/form.styles.ts
@@ -20,6 +20,7 @@ import {
   euiCanAnimate,
   euiFontSize,
 } from '../../global_styling';
+import { euiButtonColor } from '../../themes/amsterdam/global_styling/mixins';
 
 export const euiFormVariables = (euiThemeContext: UseEuiTheme) => {
   const { euiTheme, colorMode } = euiThemeContext;
@@ -59,10 +60,6 @@ export const euiFormVariables = (euiThemeContext: UseEuiTheme) => {
     controlPlaceholderText: makeHighContrastColor(euiTheme.colors.subduedText)(
       backgroundColor
     ),
-    controlAutoFillColor:
-      colorMode === 'LIGHT'
-        ? euiTheme.colors.darkestShade
-        : euiTheme.colors.lightShade,
     inputGroupLabelBackground: isColorDark
       ? shade(euiTheme.colors.lightShade, 0.15)
       : tint(euiTheme.colors.lightShade, 0.5),
@@ -167,14 +164,7 @@ export const euiFormControlStyles = (euiThemeContext: UseEuiTheme) => {
     focus: euiFormControlFocusStyles(euiThemeContext),
     disabled: euiFormControlDisabledStyles(euiThemeContext),
     readOnly: euiFormControlReadOnlyStyles(euiThemeContext),
-    autoFill: `
-      &:-webkit-autofill {
-        -webkit-text-fill-color: ${form.controlAutoFillColor};
-
-        ~ .euiFormControlLayoutIcons {
-          color: ${form.controlAutoFillColor};
-        }
-      }`,
+    autoFill: euiFormControlAutoFillStyles(euiThemeContext),
   };
 };
 
@@ -312,6 +302,41 @@ export const euiFormControlReadOnlyStyles = (euiThemeContext: UseEuiTheme) => {
   `;
 };
 
+export const euiFormControlAutoFillStyles = (euiThemeContext: UseEuiTheme) => {
+  const { euiTheme, colorMode } = euiThemeContext;
+
+  // Make the text color slightly less prominent than the default colors.text
+  const textColor = euiTheme.colors.darkestShade;
+
+  const { backgroundColor } = euiButtonColor(euiThemeContext, 'primary');
+  const tintedBackgroundColor =
+    colorMode === 'DARK'
+      ? shade(backgroundColor, 0.5)
+      : tint(backgroundColor, 0.7);
+  // Hacky workaround to background-color, since Chrome doesn't normally allow overriding its styles
+  // @see https://developer.mozilla.org/en-US/docs/Web/CSS/:autofill#sect1
+  const backgroundShadow = `inset 0 0 0 100vw ${tintedBackgroundColor}`;
+
+  // Re-create the border, since the above webkit box shadow overrides the default border box-shadow
+  // + change the border color to match states, since the underline background gradient no longer works
+  const borderColor = transparentize(euiTheme.colors.primaryText, 0.2);
+  const invalidBorder = euiTheme.colors.danger;
+  const borderShadow = (color: string) =>
+    `inset 0 0 0 ${euiTheme.border.width.thin} ${color}`;
+
+  // These styles only apply/override Chrome/webkit browsers - Firefox does not set autofill styles
+  return `
+    &:-webkit-autofill {
+      -webkit-text-fill-color: ${textColor};
+      -webkit-box-shadow: ${borderShadow(borderColor)}, ${backgroundShadow};
+
+      &:invalid {
+        -webkit-box-shadow: ${borderShadow(invalidBorder)}, ${backgroundShadow};
+      }
+    }
+  `;
+};
+
 const euiPlaceholderPerBrowser = (content: string) => `
   &::-webkit-input-placeholder { ${content} }
   &::-moz-placeholder { ${content} }