From 1dd68eb8d8798d6a476bc7b0757979276d6ea182 Mon Sep 17 00:00:00 2001 From: Cee Chen <549407+cee-chen@users.noreply.github.com> Date: Thu, 16 May 2024 11:50:47 -0700 Subject: [PATCH] [EuiBadge] Increase color contrast of selected text (+ bonus cleanup) (#7752) --- ...isplay_EuiBadge_EuiBadge_Custom_Colors.png | Bin 0 -> 1126 bytes ...isplay_EuiBadge_EuiBadge_Custom_Colors.png | Bin 0 -> 2575 bytes packages/eui/changelogs/upcoming/7752.md | 3 + .../badge/__snapshots__/badge.test.tsx.snap | 4 +- .../src/components/badge/badge.stories.tsx | 21 ++++++- .../eui/src/components/badge/badge.styles.ts | 52 +++++++++++++----- .../eui/src/components/badge/badge.test.tsx | 4 ++ packages/eui/src/components/badge/badge.tsx | 17 ++++-- 8 files changed, 76 insertions(+), 25 deletions(-) create mode 100644 packages/eui/.loki/reference/chrome_desktop_Display_EuiBadge_EuiBadge_Custom_Colors.png create mode 100644 packages/eui/.loki/reference/chrome_mobile_Display_EuiBadge_EuiBadge_Custom_Colors.png create mode 100644 packages/eui/changelogs/upcoming/7752.md diff --git a/packages/eui/.loki/reference/chrome_desktop_Display_EuiBadge_EuiBadge_Custom_Colors.png b/packages/eui/.loki/reference/chrome_desktop_Display_EuiBadge_EuiBadge_Custom_Colors.png new file mode 100644 index 0000000000000000000000000000000000000000..d6e97633e688ea3407eed7f967a4835fb89f9e25 GIT binary patch literal 1126 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 literal 0 HcmV?d00001 diff --git a/packages/eui/changelogs/upcoming/7752.md b/packages/eui/changelogs/upcoming/7752.md new file mode 100644 index 00000000000..072f090be83 --- /dev/null +++ b/packages/eui/changelogs/upcoming/7752.md @@ -0,0 +1,3 @@ +**Accessibility** + +- Improved `EuiBadge`'s ability to tell when text within the badge is selected/highlighted and selection color contrast diff --git a/packages/eui/src/components/badge/__snapshots__/badge.test.tsx.snap b/packages/eui/src/components/badge/__snapshots__/badge.test.tsx.snap index 6e8be464c31..2c41ffaaab0 100644 --- a/packages/eui/src/components/badge/__snapshots__/badge.test.tsx.snap +++ b/packages/eui/src/components/badge/__snapshots__/badge.test.tsx.snap @@ -3,7 +3,7 @@ exports[`EuiBadge is disabled 1`] = ` @@ -178,7 +178,6 @@ exports[`EuiBadge props color accent is rendered 1`] = ` exports[`EuiBadge props color accepts hex 1`] = ` = { title: 'Display/EuiBadge/EuiBadge', @@ -20,6 +20,7 @@ const meta: Meta = { // Component defaults iconSide: 'left', isDisabled: false, + color: 'default', }, }; @@ -30,4 +31,22 @@ export const Playground: Story = { args: { children: 'Badge text', }, + argTypes: { + color: { + control: 'select', + options: COLORS, + }, + }, +}; + +export const CustomColors: Story = { + parameters: { + controls: { + include: ['color', 'children', 'isDisabled'], + }, + }, + args: { + children: 'Badge text', + color: '#0000FF', + }, }; diff --git a/packages/eui/src/components/badge/badge.styles.ts b/packages/eui/src/components/badge/badge.styles.ts index bc5211b8daf..8704c3bb734 100644 --- a/packages/eui/src/components/badge/badge.styles.ts +++ b/packages/eui/src/components/badge/badge.styles.ts @@ -22,6 +22,12 @@ import { euiBadgeColors } from './color_utils'; export const euiBadgeStyles = (euiThemeContext: UseEuiTheme) => { const { euiTheme } = euiThemeContext; const badgeColors = euiBadgeColors(euiThemeContext); + const setBadgeColorVars = ( + colors: ReturnType['primary'] + ) => ` + --euiBadgeTextColor: ${colors.color}; + --euiBadgeBackgroundColor: ${colors.backgroundColor}; + `; return { euiBadge: css` @@ -39,7 +45,6 @@ export const euiBadgeStyles = (euiThemeContext: UseEuiTheme) => { white-space: nowrap; text-decoration: none; cursor: default; - background-color: transparent; border: ${euiTheme.border.width.thin} solid transparent; border-radius: ${mathWithUnits( euiTheme.border.radius.medium, @@ -49,6 +54,25 @@ export const euiBadgeStyles = (euiThemeContext: UseEuiTheme) => { So, make the text left aligned to ensure all badges line up the same */ ${logicalTextAlignCSS('left')} + /* Colors - inherit from CSS variables, which can be set via inline style */ + color: var(--euiBadgeTextColor, ${badgeColors.default.color}); + background-color: var( + --euiBadgeBackgroundColor, + ${badgeColors.default.backgroundColor} + ); + + /* Ensure that selected text is always visible by inverting badge and text colors */ + *::selection { + color: var( + --euiBadgeBackgroundColor, + ${badgeColors.default.backgroundColor} + ); + background-color: var( + --euiBadgeTextColor, + ${badgeColors.default.color} + ); + } + &:focus-within { ${euiFocusRing(euiThemeContext)} } @@ -75,25 +99,23 @@ export const euiBadgeStyles = (euiThemeContext: UseEuiTheme) => { `, // Colors - default: css(badgeColors.default), + default: css(setBadgeColorVars(badgeColors.default)), hollow: css` - color: ${badgeColors.hollow.color}; - background-color: ${badgeColors.hollow.backgroundColor}; + ${setBadgeColorVars(badgeColors.hollow)} border-color: ${badgeColors.hollow.borderColor}; `, - primary: css(badgeColors.primary), - accent: css(badgeColors.accent), - warning: css(badgeColors.warning), - danger: css(badgeColors.danger), - success: css(badgeColors.success), + primary: css(setBadgeColorVars(badgeColors.primary)), + accent: css(setBadgeColorVars(badgeColors.accent)), + warning: css(setBadgeColorVars(badgeColors.warning)), + danger: css(setBadgeColorVars(badgeColors.danger)), + success: css(setBadgeColorVars(badgeColors.success)), disabled: css` - /* stylelint-disable declaration-no-important */ + ${setBadgeColorVars(badgeColors.disabled)} - /* Using !important to override inline styles */ - color: ${badgeColors.disabled.color} !important; - background-color: ${badgeColors.disabled.backgroundColor} !important; - - /* stylelint-enable declaration-no-important */ + /* Override selection color, since disabled badges have rgba backgrounds with opacity */ + *::selection { + color: ${euiTheme.colors.emptyShade}; + } `, // Content wrapper diff --git a/packages/eui/src/components/badge/badge.test.tsx b/packages/eui/src/components/badge/badge.test.tsx index 00d0af9c924..cd8df65b7d4 100644 --- a/packages/eui/src/components/badge/badge.test.tsx +++ b/packages/eui/src/components/badge/badge.test.tsx @@ -154,12 +154,16 @@ describe('EuiBadge', () => { ); expect(container.firstChild).toMatchSnapshot(); + // NOTE: jsdom currently does not support CSS variables (@see https://github.com/testing-library/jest-dom/issues/322) + // We're relying on visual regression tests here instead }); it('accepts hex', () => { const { container } = render(Content); expect(container.firstChild).toMatchSnapshot(); + // NOTE: jsdom currently does not support CSS variables (@see https://github.com/testing-library/jest-dom/issues/322) + // We're relying on visual regression tests here instead }); }); diff --git a/packages/eui/src/components/badge/badge.tsx b/packages/eui/src/components/badge/badge.tsx index 3e3bac321f2..735576b30b6 100644 --- a/packages/eui/src/components/badge/badge.tsx +++ b/packages/eui/src/components/badge/badge.tsx @@ -132,6 +132,8 @@ export const EuiBadge: FunctionComponent = ({ const euiTheme = useEuiTheme(); const customColorStyles = useMemo(() => { + // Disabled badges should not have custom colors + if (isDisabled) return style; // Named colors set their styles via Emotion CSS and not inline styles if (isNamedColor) return style; @@ -151,8 +153,8 @@ export const EuiBadge: FunctionComponent = ({ } return { - backgroundColor: color, - color: textColor, + '--euiBadgeBackgroundColor': color, + '--euiBadgeTextColor': textColor, ...style, }; } catch (err) { @@ -164,14 +166,17 @@ export const EuiBadge: FunctionComponent = ({ ); } } - }, [color, isNamedColor, style, euiTheme]); + }, [color, isNamedColor, isDisabled, style, euiTheme]); const styles = useEuiMemoizedStyles(euiBadgeStyles); const cssStyles = [ styles.euiBadge, - isNamedColor && styles[color as BadgeColor], - (onClick || href) && !iconOnClick && styles.clickable, - isDisabled && styles.disabled, + ...(isDisabled + ? [styles.disabled] + : [ + isNamedColor && styles[color as BadgeColor], + !iconOnClick && (onClick || href) && styles.clickable, + ]), ]; const textCssStyles = [ styles.text.euiBadge__text,