diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Inline.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Inline.png index 0d22a4cfe79..f8879906597 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Inline.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Inline.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Playground.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Playground.png index 32458b11e54..0873205da4b 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Playground.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Restricted_Selection.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Restricted_Selection.png index b3b55800739..56dfac948c1 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Restricted_Selection.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePickerRange_Restricted_Selection.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Playground.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Playground.png index c4a961b6415..126090717c0 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Playground.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Restricted_Day_Select.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Restricted_Day_Select.png index bf3953d37be..e678bb6b125 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Restricted_Day_Select.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Restricted_Day_Select.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select.png index 8196c1f80c4..5a912c528f9 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select_Only.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select_Only.png index c43ab3fe28f..10a2e147d56 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select_Only.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiDatePicker_Time_Select_Only.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast.png index c9c92b8b15d..605978ae67f 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast_Dark_Mode.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast_Dark_Mode.png index 119148230ad..2d592cfe617 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast_Dark_Mode.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast_Dark_Mode.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_Kitchen_Sink.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_Kitchen_Sink.png index 654643b7bb4..b5ad8719e48 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_Kitchen_Sink.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayoutDelimited_Kitchen_Sink.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayout_Icon_Shape.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayout_Icon_Shape.png index ce375a6b3f3..d9c4f5bd6ad 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayout_Icon_Shape.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiForm_EuiFormControlLayout_Icon_Shape.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png index ffa99f4fdca..bfa5c58718e 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png differ diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Restricted_Range.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Restricted_Range.png index 585d9fdc753..b35e83f0cb4 100644 Binary files a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Restricted_Range.png and b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Restricted_Range.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Inline.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Inline.png index c8c70f08bce..f7b3be8b2ba 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Inline.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Inline.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Playground.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Playground.png index f664661b346..88226d2cdf3 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Playground.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Restricted_Selection.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Restricted_Selection.png index 963af9896c3..72fb86844dd 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Restricted_Selection.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePickerRange_Restricted_Selection.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Playground.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Playground.png index c47290a1b4b..3838df107ed 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Playground.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Playground.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Restricted_Day_Select.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Restricted_Day_Select.png index 9159441dff0..6a3adc8fa82 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Restricted_Day_Select.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Restricted_Day_Select.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select.png index a87e7ba5261..7581d33dbf4 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select_Only.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select_Only.png index adfa6857b3a..f5ceec053c4 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select_Only.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiDatePicker_Time_Select_Only.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast.png index 2b78c91ef44..9b1b1377126 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast_Dark_Mode.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast_Dark_Mode.png index 7067ec49a41..7302f496c37 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast_Dark_Mode.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_High_Contrast_Dark_Mode.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_Kitchen_Sink.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_Kitchen_Sink.png index 9258b2e3400..5791b86c9fc 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_Kitchen_Sink.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayoutDelimited_Kitchen_Sink.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayout_Icon_Shape.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayout_Icon_Shape.png index e053f335276..9ca49d0a439 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayout_Icon_Shape.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiForm_EuiFormControlLayout_Icon_Shape.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png index 6eb2a51e3d3..39429e358ba 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Custom_Quick_Select_Panel.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Restricted_Range.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Restricted_Range.png index 32277cccdf5..b216333b60e 100644 Binary files a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Restricted_Range.png and b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Restricted_Range.png differ diff --git a/packages/eui/src/components/color_picker/color_palette_display/color_palette_display.styles.ts b/packages/eui/src/components/color_picker/color_palette_display/color_palette_display.styles.ts index d15e964061b..763b1994e7a 100644 --- a/packages/eui/src/components/color_picker/color_palette_display/color_palette_display.styles.ts +++ b/packages/eui/src/components/color_picker/color_palette_display/color_palette_display.styles.ts @@ -10,6 +10,7 @@ import { css } from '@emotion/react'; import { UseEuiTheme, transparentize } from '../../../services'; import { logicalCSS } from '../../../global_styling'; +import { preventForcedColors } from '../../../global_styling/functions/high_contrast'; export const euiColorPaletteDisplayStyles = (euiThemeContext: UseEuiTheme) => { const { euiTheme, highContrastMode } = euiThemeContext; @@ -28,7 +29,7 @@ export const euiColorPaletteDisplayStyles = (euiThemeContext: UseEuiTheme) => { display: flex; flex-direction: row; overflow: hidden; - ${highContrastMode === 'forced' ? 'forced-color-adjust: none;' : ''} + ${preventForcedColors(euiThemeContext)} &::after { content: ''; diff --git a/packages/eui/src/components/color_picker/color_picker_swatch.styles.ts b/packages/eui/src/components/color_picker/color_picker_swatch.styles.ts index 78163f5f89e..537e6b8572f 100644 --- a/packages/eui/src/components/color_picker/color_picker_swatch.styles.ts +++ b/packages/eui/src/components/color_picker/color_picker_swatch.styles.ts @@ -14,9 +14,13 @@ import { mathWithUnits, euiOutline, } from '../../global_styling'; +import { + highContrastModeStyles, + preventForcedColors, +} from '../../global_styling/functions/high_contrast'; export const euiColorPickerSwatchStyles = (euiThemeContext: UseEuiTheme) => { - const { euiTheme, highContrastMode } = euiThemeContext; + const { euiTheme } = euiThemeContext; return { euiColorPickerSwatch: css` @@ -27,15 +31,16 @@ export const euiColorPickerSwatchStyles = (euiThemeContext: UseEuiTheme) => { euiTheme.border.radius.medium, (x) => x / 2 )}; - ${highContrastMode - ? `border: ${euiTheme.border.thin};` - : ` + ${highContrastModeStyles(euiThemeContext, { + none: ` border: ${euiTheme.border.width.thin} solid ${transparentize(euiTheme.colors.fullShade, 0.1)}; box-shadow: inset 0 0 0 ${euiTheme.border.width.thin} ${transparentize(euiTheme.colors.emptyShade, 0.05)}; - `} - ${highContrastMode === 'forced' ? 'forced-color-adjust: none;' : ''} + `, + preferred: `border: ${euiTheme.border.thin};`, + forced: preventForcedColors(euiThemeContext), + })} cursor: pointer; &:disabled { diff --git a/packages/eui/src/components/color_picker/hue.styles.ts b/packages/eui/src/components/color_picker/hue.styles.ts index a5fb6021ba1..5cbf66c581e 100644 --- a/packages/eui/src/components/color_picker/hue.styles.ts +++ b/packages/eui/src/components/color_picker/hue.styles.ts @@ -10,6 +10,10 @@ import { css } from '@emotion/react'; import { UseEuiTheme, transparentize } from '../../services'; import { logicalCSS, mathWithUnits } from '../../global_styling'; +import { + highContrastModeStyles, + preventForcedColors, +} from '../../global_styling/functions/high_contrast'; import { euiRangeThumbPerBrowser, euiRangeThumbStyle, @@ -17,7 +21,7 @@ import { } from '../form/range/range.styles'; export const euiHueStyles = (euiThemeContext: UseEuiTheme) => { - const { euiTheme, highContrastMode } = euiThemeContext; + const { euiTheme } = euiThemeContext; const height = euiTheme.size.m; const thumbSize = euiTheme.size.l; @@ -33,12 +37,10 @@ export const euiHueStyles = (euiThemeContext: UseEuiTheme) => { // This wraps the range and sets a rainbow gradient, // which allows the range thumb to be larger than the visible track euiHue: css` - /* stylelint-disable color-no-hex */ ${logicalCSS('height', height)} border-radius: ${height}; - ${highContrastMode ? `border: ${euiTheme.border.thin};` : ''} - ${highContrastMode === 'forced' ? 'forced-color-adjust: none;' : ''} + /* stylelint-disable color-no-hex */ background: linear-gradient( to right, #ff3232 0%, @@ -50,6 +52,11 @@ export const euiHueStyles = (euiThemeContext: UseEuiTheme) => { #ff0094 100% ); /* stylelint-enable color-no-hex */ + + ${highContrastModeStyles(euiThemeContext, { + preferred: `border: ${euiTheme.border.thin};`, + forced: preventForcedColors(euiThemeContext), + })} `, euiHue__range: css` @@ -76,38 +83,42 @@ export const euiHueStyles = (euiThemeContext: UseEuiTheme) => { ${euiRangeThumbPerBrowser(` ${euiRangeThumbStyle(euiThemeContext)} border-width: ${thumbBorder}; - ${ - highContrastMode - ? ` + + ${highContrastModeStyles(euiThemeContext, { + none: ` + background-color: transparent; + box-shadow: ${thumbBoxShadow}; + `, + preferred: ` background-color: ${euiTheme.colors.ghost}; border: ${thumbBorder} solid ${euiTheme.colors.ink}; box-shadow: none; - ` - : ` - background-color: transparent; - box-shadow: ${thumbBoxShadow}; - ` - }`)} + `, + })} + `)} /* Remove wrapping outline and show focus on thumb only */ &:focus { outline: none; } - ${highContrastMode - ? ` - &:focus { - ${euiRangeThumbPerBrowser(` - outline: ${euiTheme.border.width.thin} solid ${euiTheme.colors.ink}; - outline-offset: 0; - `)} - }` - : ` - &:focus-visible { - ${euiRangeThumbPerBrowser( - euiRangeThumbFocusBoxShadow(euiThemeContext) - )} - }`} + ${highContrastModeStyles(euiThemeContext, { + none: ` + &:focus-visible { + ${euiRangeThumbPerBrowser( + euiRangeThumbFocusBoxShadow(euiThemeContext) + )} + } + `, + preferred: ` + &:focus { + ${euiRangeThumbPerBrowser(` + outline: ${euiTheme.border.width.thin} solid ${euiTheme.colors.ink}; + outline-offset: 0; + `)} + } + `, + })} `, }; }; diff --git a/packages/eui/src/components/color_picker/saturation.styles.ts b/packages/eui/src/components/color_picker/saturation.styles.ts index 2bbd91eaa66..39d78f8165b 100644 --- a/packages/eui/src/components/color_picker/saturation.styles.ts +++ b/packages/eui/src/components/color_picker/saturation.styles.ts @@ -14,9 +14,13 @@ import { logicalSizeCSS, mathWithUnits, } from '../../global_styling'; +import { + highContrastModeStyles, + preventForcedColors, +} from '../../global_styling/functions/high_contrast'; export const euiSaturationStyles = (euiThemeContext: UseEuiTheme) => { - const { euiTheme, highContrastMode } = euiThemeContext; + const { euiTheme } = euiThemeContext; const indicatorSize = euiTheme.size.m; const borderRadius = euiTheme.border.radius.small; @@ -38,23 +42,25 @@ export const euiSaturationStyles = (euiThemeContext: UseEuiTheme) => { outline: none; /* Hide focus ring from tabindex=0 */ .euiSaturation__indicator { - ${highContrastMode - ? ` - outline: ${euiTheme.border.width.thin} solid ${euiTheme.colors.ink}; - outline-offset: 0;` - : ` + ${highContrastModeStyles(euiThemeContext, { + none: ` outline: none; /* Standardize indicator focus ring */ box-shadow: 0 0 0 ${euiTheme.focus.width} ${euiTheme.colors.primary}; border-color: ${euiTheme.colors.primary}; - `} + `, + preferred: ` + outline: ${euiTheme.border.width.thin} solid ${euiTheme.colors.ink}; + outline-offset: 0; + `, + })} } } - ${highContrastMode === 'forced' ? 'forced-color-adjust: none;' : ''} - ${highContrastMode - ? // The border must be in an overlaid pseudo element to not affect the - // width/height and position of the indicator, or cause border-radius issues - `&::after { + ${highContrastModeStyles(euiThemeContext, { + // The border must be in an overlaid pseudo element to not affect the + // width/height/position of the indicator, or cause border-radius issues + preferred: ` + &::after { z-index: 1; content: ''; position: absolute; @@ -62,8 +68,10 @@ export const euiSaturationStyles = (euiThemeContext: UseEuiTheme) => { border: ${euiTheme.border.thin}; border-radius: inherit; pointer-events: none; - }` - : ''} + } + `, + forced: preventForcedColors(euiThemeContext), + })} `, euiSaturation__lightness: css` @@ -89,21 +97,25 @@ export const euiSaturationStyles = (euiThemeContext: UseEuiTheme) => { ${logicalSizeCSS(indicatorSize)} transform: translateX(-50%) translateY(-50%); border-radius: 100%; - ${highContrastMode - ? ` - border: ${euiTheme.border.width.thick} solid ${euiTheme.colors.ink}; - background-color: ${euiTheme.colors.ghost};` - : ` - border: ${euiTheme.border.width.thin} solid ${euiTheme.colors.darkestShade}; - &::before { - content: ''; - position: absolute; - inset: 0; - border-radius: 100%; - border: ${euiTheme.border.width.thin} solid - ${euiTheme.colors.lightestShade}; - }`} + ${highContrastModeStyles(euiThemeContext, { + none: ` + border: ${euiTheme.border.width.thin} solid ${euiTheme.colors.darkestShade}; + + &::before { + content: ''; + position: absolute; + inset: 0; + border-radius: 100%; + border: ${euiTheme.border.width.thin} solid + ${euiTheme.colors.lightestShade}; + } + `, + preferred: ` + border: ${euiTheme.border.width.thick} solid ${euiTheme.colors.ink}; + background-color: ${euiTheme.colors.ghost}; + `, + })} `, }; }; diff --git a/packages/eui/src/components/date_picker/react_date_picker.styles.ts b/packages/eui/src/components/date_picker/react_date_picker.styles.ts index 36c19f87654..bc7e6944fd6 100644 --- a/packages/eui/src/components/date_picker/react_date_picker.styles.ts +++ b/packages/eui/src/components/date_picker/react_date_picker.styles.ts @@ -8,6 +8,9 @@ // Needs to use vanilla `css` to pass a className directly to react-datepicker import { css } from '@emotion/css'; +// Emotion can handle serializing objects passed directly to css``, but not objs nested +// in another function util, so we need to serialize some style objects manually +import { serializeStyles } from '@emotion/serialize'; import { UseEuiTheme } from '../../services'; import { @@ -18,6 +21,10 @@ import { logicalCSS, mathWithUnits, } from '../../global_styling'; +import { + highContrastModeStyles, + preventForcedColors, +} from '../../global_styling/functions/high_contrast'; import { euiButtonColor, euiButtonEmptyColor, @@ -232,7 +239,7 @@ export const _monthYearDropdowns = (euiThemeContext: UseEuiTheme) => { }; export const _dayCalendarStyles = (euiThemeContext: UseEuiTheme) => { - const { euiTheme, highContrastMode } = euiThemeContext; + const { euiTheme } = euiThemeContext; const { gapSize } = euiDatePickerVariables(euiThemeContext); const daySize = euiTheme.size.xl; @@ -295,9 +302,11 @@ export const _dayCalendarStyles = (euiThemeContext: UseEuiTheme) => { &--highlighted, &--highlighted:hover { - ${highContrastMode !== 'forced' - ? euiButtonColor(euiThemeContext, 'success') - : `border: ${euiTheme.border.thin};`} + ${highContrastModeStyles(euiThemeContext, { + none: serializeStyles([euiButtonColor(euiThemeContext, 'success')]) + .styles, + forced: `border: ${euiTheme.border.thin};`, + })} } &--in-range, @@ -305,10 +314,10 @@ export const _dayCalendarStyles = (euiThemeContext: UseEuiTheme) => { ${euiButtonColor(euiThemeContext, 'primary')}; } - ${highContrastMode !== 'forced' - ? // Ranges use 2 side box-shadows that are the same as the button - //background to fill the gap between margins - ` + ${highContrastModeStyles(euiThemeContext, { + // Ranges use 2 side box-shadows that are the same as the button + // background to fill the gap between margins + none: ` &--in-range:not(&--selected):not(:hover):not(&--disabled) { box-shadow: -${rangeMarginOffset} 0 ${rangeBackgroundColor}, ${rangeMarginOffset} 0 ${rangeBackgroundColor}; @@ -330,9 +339,10 @@ export const _dayCalendarStyles = (euiThemeContext: UseEuiTheme) => { border-radius ${animationSpeed} ease-in-out, background-color ${animationSpeed} ease-in; } - }` - : // In Windows high contrast mode, use borders and pseudo elements instead of background colors - ` + } + `, + // In Windows high contrast mode, use borders and pseudo elements instead of background colors + forced: ` &--in-range:not(&--selected) { position: relative; transform: none; @@ -350,7 +360,9 @@ export const _dayCalendarStyles = (euiThemeContext: UseEuiTheme) => { } &--range-end:not(&--selected)::before { border-inline-end: ${euiTheme.border.thin}; - }`} + } + `, + })} &--selected, &--selected:hover, @@ -361,9 +373,11 @@ export const _dayCalendarStyles = (euiThemeContext: UseEuiTheme) => { &--disabled, &--disabled:hover { - ${highContrastMode !== 'forced' - ? euiButtonColor(euiThemeContext, 'disabled') - : 'opacity: 0.5;'} + ${highContrastModeStyles(euiThemeContext, { + none: serializeStyles([euiButtonColor(euiThemeContext, 'disabled')]) + .styles, + forced: `opacity: 0.5;`, + })} cursor: not-allowed; text-decoration: none; transform: none; @@ -380,14 +394,16 @@ export const _dayCalendarStyles = (euiThemeContext: UseEuiTheme) => { &--in-selecting-range:not(&--in-range), &--disabled.react-datepicker__day--selected, &--disabled.react-datepicker__day--selected:hover { - ${highContrastMode !== 'forced' - ? euiButtonColor(euiThemeContext, 'danger') - : ` + ${highContrastModeStyles(euiThemeContext, { + none: serializeStyles([euiButtonColor(euiThemeContext, 'danger')]) + .styles, + forced: ` color: ${euiTheme.colors.dangerText}; border: ${euiTheme.border.width.thin} solid ${euiTheme.colors.dangerText}; background-color: ${euiTheme.colors.emptyShade}; opacity: 1; - `} + `, + })} } } `; @@ -505,6 +521,6 @@ const _highContrastSelected = (euiThemeContext: UseEuiTheme) => { : ` background-color: ${euiTheme.colors.fullShade}; color: ${euiTheme.colors.emptyShade}; - forced-color-adjust: none; + ${preventForcedColors(euiThemeContext)} `; }; diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.styles.ts b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.styles.ts index 70a257b4b1b..74c4c637c44 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.styles.ts +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.styles.ts @@ -20,6 +20,7 @@ import { logicalCSS, mathWithUnits, } from '../../../global_styling'; +import { highContrastModeStyles } from '../../../global_styling/functions/high_contrast'; import { euiFormVariables, euiFormControlDefaultShadow, @@ -29,7 +30,7 @@ import { } from '../../form/form.styles'; export const euiSuperDatePickerStyles = (euiThemeContext: UseEuiTheme) => { - const { euiTheme, colorMode, highContrastMode } = euiThemeContext; + const { euiTheme, colorMode } = euiThemeContext; const forms = euiFormVariables(euiThemeContext); const inputWidth = euiTheme.base * 30; @@ -142,7 +143,10 @@ export const euiSuperDatePickerStyles = (euiThemeContext: UseEuiTheme) => { euiSuperDatePicker__formControlLayout: css` .euiFormControlLayout__childrenWrapper { ${euiFormControlDefaultShadow(euiThemeContext)} - ${highContrastMode ? 'border: none' : 'box-shadow: none'}; + ${highContrastModeStyles(euiThemeContext, { + none: 'box-shadow: none;', + preferred: 'border: none;', + })} } `, default: css` @@ -207,15 +211,16 @@ export const euiSuperDatePickerStyles = (euiThemeContext: UseEuiTheme) => { )} } - ${highContrastMode === 'forced' - ? // Force the fill color of all icons/svgs to give a bit more indication of state, - // since Windows high contrast themes otherwise override background/text color - ` - svg, - & + * svg { - fill: ${euiTheme.colors.success}; - }` - : ''} + ${highContrastModeStyles(euiThemeContext, { + // Force the fill color of all icons/svgs to give a bit more indication of state, + // since Windows high contrast themes otherwise override background/text color + forced: ` + svg, + & + * svg { + fill: ${euiTheme.colors.success}; + } + `, + })} `, }, }; diff --git a/packages/eui/src/components/form/form.styles.test.tsx b/packages/eui/src/components/form/form.styles.test.tsx index c2770916b66..6f4f22a35b8 100644 --- a/packages/eui/src/components/form/form.styles.test.tsx +++ b/packages/eui/src/components/form/form.styles.test.tsx @@ -186,16 +186,16 @@ describe('euiFormControlStyles', () => { border: none; - box-shadow: inset 0 0 0 1px rgba(32,38,47,0.1); + box-shadow: inset 0 0 0 1px rgba(32,38,47,0.1); background-color: #f9fbfd; background-repeat: no-repeat; - background-size: 0% 100%; - background-image: linear-gradient(to top, - var(--euiFormControlStateColor), - var(--euiFormControlStateColor) 2px, - transparent 2px, - transparent 100% - ); + background-size: 0% 100%; + background-image: linear-gradient(to top, + var(--euiFormControlStateColor), + var(--euiFormControlStateColor) 2px, + transparent 2px, + transparent 100% + ); @media screen and (prefers-reduced-motion: no-preference) { transition: background-image 150ms ease-in, diff --git a/packages/eui/src/components/form/form.styles.ts b/packages/eui/src/components/form/form.styles.ts index aaa6c517a3d..679252d78c1 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 { highContrastModeStyles } from '../../global_styling/functions/high_contrast'; import { euiButtonColor } from '../../themes/amsterdam/global_styling/mixins'; // There are multiple components that only need the form max-width size & @@ -107,7 +108,6 @@ export const euiFormVariables = (euiThemeContext: UseEuiTheme) => { }; export const euiFormControlStyles = (euiThemeContext: UseEuiTheme) => { - const { highContrastMode } = euiThemeContext; const form = euiFormVariables(euiThemeContext); return { @@ -147,7 +147,10 @@ export const euiFormControlStyles = (euiThemeContext: UseEuiTheme) => { // In group inGroup: ` ${logicalCSS('height', '100%')} - ${highContrastMode ? 'border: none' : 'box-shadow: none'}; + ${highContrastModeStyles(euiThemeContext, { + none: 'box-shadow: none;', + preferred: 'border: none;', + })} border-radius: 0; `, @@ -201,41 +204,44 @@ export const euiFormControlDefaultShadow = ( withBackgroundAnimation?: boolean; } = {} ) => { - const { euiTheme, highContrastMode } = euiThemeContext; + const { euiTheme } = euiThemeContext; const form = euiFormVariables(euiThemeContext); - // We use inset box-shadow instead of border to skip extra height calculations - const border = !highContrastMode - ? ` - border: none; - box-shadow: inset 0 0 0 ${euiTheme.border.width.thin} ${form.borderColor}; - `.trim() - : // In high contrast mode, this doesn't matter - we need to prioritize visibility - `border: ${euiTheme.border.width.thin} solid ${euiTheme.border.color};`; + const border = highContrastModeStyles(euiThemeContext, { + // We use inset box-shadow instead of border to skip extra height calculations + none: ` + border: none; + box-shadow: inset 0 0 0 ${euiTheme.border.width.thin} ${form.borderColor}; + `, + // In high contrast mode, this doesn't matter - we need to prioritize visibility + preferred: ` + border: ${euiTheme.border.width.thin} solid ${euiTheme.border.color}; + `, + }); const backgroundColor = ` background-color: ${form.backgroundColor}; `.trim(); - const backgroundGradient = + const backgroundGradient = highContrastModeStyles(euiThemeContext, { + none: ` + background-repeat: no-repeat; + background-size: 0% 100%; + background-image: linear-gradient(to top, + var(--euiFormControlStateColor), + var(--euiFormControlStateColor) ${form.stateUnderlineHeight}, + transparent ${form.stateUnderlineHeight}, + transparent 100% + ); + `, // Windows high contrast mode overrides/hides background gradients - we'll need another approach - highContrastMode !== 'forced' - ? ` - background-repeat: no-repeat; - background-size: 0% 100%; - background-image: linear-gradient(to top, - var(--euiFormControlStateColor), - var(--euiFormControlStateColor) ${form.stateUnderlineHeight}, - transparent ${form.stateUnderlineHeight}, - transparent 100% - ); - `.trim() - : ` - background-repeat: no-repeat; - background-size: 0% ${form.stateUnderlineHeight}; - background-position: bottom left; - background-origin: border-box; - `.trim(); + forced: ` + background-repeat: no-repeat; + background-size: 0% ${form.stateUnderlineHeight}; + background-position: bottom left; + background-origin: border-box; + `, + }); const backgroundAnimation = ` ${euiCanAnimate} { @@ -298,7 +304,6 @@ export const euiFormControlDisabledStyles = (euiThemeContext: UseEuiTheme) => { export const euiFormControlReadOnlyStyles = (euiThemeContext: UseEuiTheme) => { const form = euiFormVariables(euiThemeContext); - const { highContrastMode } = euiThemeContext; return ` cursor: default; @@ -307,7 +312,9 @@ export const euiFormControlReadOnlyStyles = (euiThemeContext: UseEuiTheme) => { background-color: ${form.backgroundReadOnlyColor}; --euiFormControlStateColor: transparent; - ${highContrastMode === 'forced' ? 'background-image: none;' : ''} + ${highContrastModeStyles(euiThemeContext, { + forced: 'background-image: none;', + })} `; }; diff --git a/packages/eui/src/components/form/form_control_layout/form_control_layout.styles.ts b/packages/eui/src/components/form/form_control_layout/form_control_layout.styles.ts index eaf72ce4c7a..59bf66a7d93 100644 --- a/packages/eui/src/components/form/form_control_layout/form_control_layout.styles.ts +++ b/packages/eui/src/components/form/form_control_layout/form_control_layout.styles.ts @@ -14,6 +14,7 @@ import { logicalCSS, mathWithUnits, } from '../../../global_styling'; +import { highContrastModeStyles } from '../../../global_styling/functions/high_contrast'; import { euiFormVariables } from '../form.styles'; @@ -86,7 +87,7 @@ export const euiFormControlLayoutStyles = (euiThemeContext: UseEuiTheme) => { export const euiFormControlLayoutSideNodeStyles = ( euiThemeContext: UseEuiTheme ) => { - const { euiTheme, highContrastMode } = euiThemeContext; + const { euiTheme } = euiThemeContext; const form = euiFormVariables(euiThemeContext); const uncompressedHeight = mathWithUnits( @@ -141,14 +142,16 @@ export const euiFormControlLayoutSideNodeStyles = ( ${logicalCSS('padding-right', euiTheme.size.s)} } `, - append: css` - ${highContrastMode ? logicalCSS('border-left', euiTheme.border.thin) : ''} - `, - prepend: css` - ${highContrastMode - ? logicalCSS('border-right', euiTheme.border.thin) - : ''} - `, + append: css( + highContrastModeStyles(euiThemeContext, { + preferred: logicalCSS('border-left', euiTheme.border.thin), + }) + ), + prepend: css( + highContrastModeStyles(euiThemeContext, { + preferred: logicalCSS('border-right', euiTheme.border.thin), + }) + ), uncompressed: ` ${text} { ${logicalCSS('padding-horizontal', euiTheme.size.xs)} diff --git a/packages/eui/src/components/form/range/range.styles.ts b/packages/eui/src/components/form/range/range.styles.ts index dc5a2ce4d37..5fa02cde28e 100644 --- a/packages/eui/src/components/form/range/range.styles.ts +++ b/packages/eui/src/components/form/range/range.styles.ts @@ -9,6 +9,10 @@ import { css } from '@emotion/react'; import { UseEuiTheme, hexToRgb } from '../../../services'; import { mathWithUnits } from '../../../global_styling'; +import { + highContrastModeStyles, + preventForcedColors, +} from '../../../global_styling/functions/high_contrast'; import { euiFormVariables } from '../form.styles'; export const euiRangeVariables = (euiThemeContext: UseEuiTheme) => { @@ -118,7 +122,7 @@ export const euiRangeThumbFocusBoxShadow = (euiThemeContext: UseEuiTheme) => { export const euiRangeThumbStyle = (euiThemeContext: UseEuiTheme) => { const range = euiRangeVariables(euiThemeContext); - const { highContrastMode, euiTheme } = euiThemeContext; + const { euiTheme } = euiThemeContext; const baseStyles = ` border-radius: 50%; @@ -129,20 +133,23 @@ export const euiRangeThumbStyle = (euiThemeContext: UseEuiTheme) => { box-sizing: border-box; // required for firefox or the border makes the width and height to increase `; - return !highContrastMode - ? ` - ${baseStyles} - background-color: var(--euiRangeThumbColor, ${range.thumbBackgroundColor}); - ${euiRangeThumbBoxShadow(euiThemeContext)}; - ${euiRangeThumbBorder(euiThemeContext)}; - ` - : ` - ${baseStyles} - forced-color-adjust: none; - background-color: var(--euiRangeThumbColor, ${euiTheme.colors.emptyShade}); - border: ${range.thumbBorderWidth} solid var(--euiRangeThumbColor, ${euiTheme.colors.fullShade}); - box-shadow: inset 0 0 0 ${range.thumbBorderWidth} ${euiTheme.colors.emptyShade}; - `; + return highContrastModeStyles(euiThemeContext, { + none: ` + ${baseStyles} + background-color: var(--euiRangeThumbColor, ${ + range.thumbBackgroundColor + }); + ${euiRangeThumbBoxShadow(euiThemeContext)}; + ${euiRangeThumbBorder(euiThemeContext)}; + `, + preferred: ` + ${baseStyles} + background-color: var(--euiRangeThumbColor, ${euiTheme.colors.emptyShade}); + border: ${range.thumbBorderWidth} solid var(--euiRangeThumbColor, ${euiTheme.colors.fullShade}); + box-shadow: inset 0 0 0 ${range.thumbBorderWidth} ${euiTheme.colors.emptyShade}; + `, + forced: preventForcedColors(euiThemeContext), + }); }; export const euiRangeThumbPerBrowser = (content: string) => { diff --git a/packages/eui/src/components/form/range/range_highlight.styles.ts b/packages/eui/src/components/form/range/range_highlight.styles.ts index a58d174681b..7cb3b60bd10 100644 --- a/packages/eui/src/components/form/range/range_highlight.styles.ts +++ b/packages/eui/src/components/form/range/range_highlight.styles.ts @@ -8,6 +8,8 @@ import { css } from '@emotion/react'; import { UseEuiTheme } from '../../../services'; +import { preventForcedColors } from '../../../global_styling/functions/high_contrast'; + import { euiRangeVariables } from './range.styles'; export const euiRangeHighlightStyles = (euiThemeContext: UseEuiTheme) => { @@ -33,7 +35,6 @@ export const euiRangeHighlightStyles = (euiThemeContext: UseEuiTheme) => { export const euiRangeHighlightProgressStyles = ( euiThemeContext: UseEuiTheme ) => { - const { highContrastMode } = euiThemeContext; const range = euiRangeVariables(euiThemeContext); return { @@ -41,7 +42,7 @@ export const euiRangeHighlightProgressStyles = ( block-size: ${range.highlightHeight}; border-radius: ${range.trackBorderRadius}; background-color: ${range.highlightColor}; - ${highContrastMode === 'forced' ? 'forced-color-adjust: none;' : ''} + ${preventForcedColors(euiThemeContext)} /* Change highlight color to focus on keyboard focus and on mouse drag */ .euiRangeSlider:focus-visible ~ .euiRangeHighlight &, diff --git a/packages/eui/src/components/form/range/range_levels.styles.ts b/packages/eui/src/components/form/range/range_levels.styles.ts index 7cb279b6b33..d182736be5e 100644 --- a/packages/eui/src/components/form/range/range_levels.styles.ts +++ b/packages/eui/src/components/form/range/range_levels.styles.ts @@ -8,12 +8,13 @@ import { css } from '@emotion/react'; import { UseEuiTheme, transparentize } from '../../../services'; +import { preventForcedColors } from '../../../global_styling/functions/high_contrast'; import { euiRangeLevelColor } from './range_levels_colors'; import { euiRangeVariables } from './range.styles'; export const euiRangeLevelsStyles = (euiThemeContext: UseEuiTheme) => { - const { euiTheme, colorMode, highContrastMode } = euiThemeContext; + const { euiTheme, colorMode } = euiThemeContext; const range = euiRangeVariables(euiThemeContext); const isColorDark = colorMode === 'DARK'; @@ -35,7 +36,7 @@ export const euiRangeLevelsStyles = (euiThemeContext: UseEuiTheme) => { inset-inline: 0; inset-block-start: ${range.trackTopPositionWithoutTicks}; z-index: ${range.levelsZIndex}; - ${highContrastMode === 'forced' ? 'forced-color-adjust: none;' : ''} + ${preventForcedColors(euiThemeContext)} `, hasRange: css` &::after { diff --git a/packages/eui/src/components/form/range/range_ticks.styles.ts b/packages/eui/src/components/form/range/range_ticks.styles.ts index a176092e1ab..2c9714f1966 100644 --- a/packages/eui/src/components/form/range/range_ticks.styles.ts +++ b/packages/eui/src/components/form/range/range_ticks.styles.ts @@ -14,27 +14,30 @@ import { euiFontSize, mathWithUnits, } from '../../../global_styling'; +import { highContrastModeStyles } from '../../../global_styling/functions/high_contrast'; + import { euiRangeVariables } from './range.styles'; const tickStyles = ( - { euiTheme, highContrastMode }: UseEuiTheme, + euiThemeContext: UseEuiTheme, range: ReturnType ) => { + const { euiTheme } = euiThemeContext; return ` position: absolute; ${logicalCSS('top', 0)}; block-size: ${range.tickHeight}; - ${ - highContrastMode !== 'forced' - ? ` - inline-size: ${range.tickWidth}; - background-color: ${range.tickColor}; - ` - : logicalCSS( - 'border-left', - `${range.tickWidth} solid ${range.tickColor}` - ) // Windows high contrast themes ignore background color but render borders - } + ${highContrastModeStyles(euiThemeContext, { + none: ` + inline-size: ${range.tickWidth}; + background-color: ${range.tickColor}; + `, + // Windows high contrast themes ignore background color but render borders + forced: logicalCSS( + 'border-left', + `${range.tickWidth} solid ${range.tickColor}` + ), + })} border-radius: ${euiTheme.border.radius.small}; `; }; diff --git a/packages/eui/src/components/form/range/range_track.styles.ts b/packages/eui/src/components/form/range/range_track.styles.ts index 013d25121db..4fea7890eb9 100644 --- a/packages/eui/src/components/form/range/range_track.styles.ts +++ b/packages/eui/src/components/form/range/range_track.styles.ts @@ -8,10 +8,10 @@ import { css } from '@emotion/react'; import { UseEuiTheme } from '../../../services'; +import { highContrastModeStyles } from '../../../global_styling/functions/high_contrast'; import { euiRangeVariables } from './range.styles'; export const euiRangeTrackStyles = (euiThemeContext: UseEuiTheme) => { - const { highContrastMode } = euiThemeContext; const range = euiRangeVariables(euiThemeContext); return { @@ -29,15 +29,17 @@ export const euiRangeTrackStyles = (euiThemeContext: UseEuiTheme) => { inset-block-start: ${range.trackTopPositionWithoutTicks}; inset-inline-start: 0; inline-size: ${range.trackWidth}; - ${ - highContrastMode !== 'forced' - ? ` - background: ${range.trackColor}; - block-size: ${range.trackHeight};` - : ` - border-block-start: ${range.trackHeight} solid ${range.trackColor}; - opacity: 0.25;` // Windows high contrast themes ignore background color, but will render borders - } + ${highContrastModeStyles(euiThemeContext, { + none: ` + background: ${range.trackColor}; + block-size: ${range.trackHeight}; + `, + // Windows high contrast themes ignore background color, but will render borders + forced: ` + border-block-start: ${range.trackHeight} solid ${range.trackColor}; + opacity: 0.25; + `, + })} border-radius: ${range.trackBorderRadius}; } `, diff --git a/packages/eui/src/components/form/switch/switch.styles.ts b/packages/eui/src/components/form/switch/switch.styles.ts index e5b216aece3..63f4a0fe62b 100644 --- a/packages/eui/src/components/form/switch/switch.styles.ts +++ b/packages/eui/src/components/form/switch/switch.styles.ts @@ -17,6 +17,10 @@ import { logicalSizeCSS, mathWithUnits, } from '../../../global_styling'; +import { + highContrastModeStyles, + preventForcedColors, +} from '../../../global_styling/functions/high_contrast'; import { euiFormCustomControlVariables } from '../form.styles'; const euiSwitchVars = (euiThemeContext: UseEuiTheme) => { @@ -145,9 +149,11 @@ const buttonStyles = ( }; const bodyStyles = ( - { colorMode, highContrastMode, euiTheme }: UseEuiTheme, + euiThemeContext: UseEuiTheme, { colors }: EuiSwitchVars ) => { + const { colorMode, euiTheme } = euiThemeContext; + // This is probably very extra, but the visual weight of the default // disabled custom control feels different in light mode depending // on the size of the switch, so I'm tinting it based on that. @@ -157,7 +163,9 @@ const bodyStyles = ( background-color: ${colorMode === 'DARK' ? colors.disabled : tint(colors.disabled, tintAmount)}; - ${highContrastMode ? `border: ${euiTheme.border.thin};` : ''} + ${highContrastModeStyles(euiThemeContext, { + preferred: `border: ${euiTheme.border.thin};`, + })} `; return { @@ -167,19 +175,21 @@ const bodyStyles = ( overflow: hidden; border-radius: inherit; pointer-events: none; /* Required for Kibana's Selenium driver to be able to click switches in FTR tests */ - ${highContrastMode === 'forced' // Windows high contrast mode - ? `border: ${euiTheme.border.thin};` - : ''} + ${highContrastModeStyles(euiThemeContext, { + forced: `border: ${euiTheme.border.thin};`, + })} `, - on: - highContrastMode === 'forced' - ? css` - background-color: ${euiTheme.border.color}; - forced-color-adjust: none; - ` - : css` - background-color: ${colors.on}; - `, + on: css( + highContrastModeStyles(euiThemeContext, { + none: ` + background-color: ${colors.on}; + `, + forced: ` + background-color: ${euiTheme.border.color}; + ${preventForcedColors(euiThemeContext)} + `, + }) + ), off: css` background-color: ${colors.off}; `, diff --git a/packages/eui/src/components/panel/panel.styles.ts b/packages/eui/src/components/panel/panel.styles.ts index 2beb090d478..27222c37d2a 100644 --- a/packages/eui/src/components/panel/panel.styles.ts +++ b/packages/eui/src/components/panel/panel.styles.ts @@ -14,9 +14,10 @@ import { logicalCSS, logicalTextAlignCSS, } from '../../global_styling'; +import { highContrastModeStyles } from '../../global_styling/functions/high_contrast'; export const euiPanelStyles = (euiThemeContext: UseEuiTheme) => { - const { euiTheme, highContrastMode } = euiThemeContext; + const { euiTheme } = euiThemeContext; return { // Base @@ -61,10 +62,13 @@ export const euiPanelStyles = (euiThemeContext: UseEuiTheme) => { &:hover, &:focus { - ${highContrastMode - ? // Use drop-shadow instead of box-shadow, as Windows high contrast themes ignores box-shadows - `filter: drop-shadow(0 ${euiTheme.border.width.thick} 0 ${euiTheme.border.color});` - : euiShadow(euiThemeContext, 'l')} + ${highContrastModeStyles(euiThemeContext, { + none: euiShadow(euiThemeContext, 'l'), + // Windows high contrast themes ignore box-shadows - use a filter workaround instead + forced: ` + filter: drop-shadow(0 ${euiTheme.border.width.thick} 0 ${euiTheme.border.color}); + `, + })} transform: translateY(-2px); cursor: pointer; } diff --git a/packages/eui/src/components/panel/split_panel/split_panel.styles.ts b/packages/eui/src/components/panel/split_panel/split_panel.styles.ts index f89340b8c82..7352b5f7e1e 100644 --- a/packages/eui/src/components/panel/split_panel/split_panel.styles.ts +++ b/packages/eui/src/components/panel/split_panel/split_panel.styles.ts @@ -9,6 +9,7 @@ import { css } from '@emotion/react'; import { logicalCSS } from '../../../global_styling'; +import { highContrastModeStyles } from '../../../global_styling/functions/high_contrast'; import { UseEuiTheme } from '../../../services'; export const euiSplitPanelOuterStyles = { @@ -25,9 +26,7 @@ export const euiSplitPanelOuterStyles = { `, }; -export const euiSplitPanelInnerStyles = ({ - highContrastMode, -}: UseEuiTheme) => ({ +export const euiSplitPanelInnerStyles = (euiThemeContext: UseEuiTheme) => ({ euiSplitPanelInner: css` /* Make sure they're evenly split */ flex-basis: 0%; @@ -37,7 +36,9 @@ export const euiSplitPanelInnerStyles = ({ transform: none !important; box-shadow: none !important; - /* Don't double up on borders in high contrast mode */ - ${highContrastMode ? 'border: none;' : ''} + ${highContrastModeStyles(euiThemeContext, { + // Don't double up on borders in high contrast mode + preferred: 'border: none;', + })} `, }); diff --git a/packages/eui/src/components/resizable_container/resizable_panel.styles.ts b/packages/eui/src/components/resizable_container/resizable_panel.styles.ts index 1ca29022a9f..b992896267f 100644 --- a/packages/eui/src/components/resizable_container/resizable_panel.styles.ts +++ b/packages/eui/src/components/resizable_container/resizable_panel.styles.ts @@ -12,6 +12,7 @@ import { logicalCSSWithFallback, euiScrollBarStyles, } from '../../global_styling'; +import { highContrastModeStyles } from '../../global_styling/functions/high_contrast'; import { UseEuiTheme } from '../../services'; export const euiResizablePanelStyles = { @@ -26,13 +27,16 @@ export const euiResizablePanelStyles = { export const euiResizablePanelContentStyles = ( euiThemeContext: UseEuiTheme ) => { - const { euiTheme, highContrastMode } = euiThemeContext; + const { euiTheme } = euiThemeContext; return { euiResizablePanel__content: css` ${logicalCSS('height', '100%')} - /* Disable default high contrast borders - they make the resize indicators too hard to see */ - ${highContrastMode ? 'border: none;' : ''} + + ${highContrastModeStyles(euiThemeContext, { + // Disable default high contrast borders - they make the resize indicators too hard to see + preferred: 'border: none;', + })} `, scrollable: css` ${euiScrollBarStyles(euiThemeContext)} diff --git a/packages/eui/src/components/toast/toast.styles.ts b/packages/eui/src/components/toast/toast.styles.ts index bafea840790..dba677a5814 100644 --- a/packages/eui/src/components/toast/toast.styles.ts +++ b/packages/eui/src/components/toast/toast.styles.ts @@ -12,6 +12,10 @@ import { logicalCSS, mathWithUnits, } from '../../global_styling'; +import { + highContrastModeStyles, + preventForcedColors, +} from '../../global_styling/functions/high_contrast'; import { UseEuiTheme } from '../../services'; import { euiShadowLarge } from '../../themes/amsterdam'; import { euiTitle } from '../title/title.styles'; @@ -53,10 +57,12 @@ export const euiToastStyles = (euiThemeContext: UseEuiTheme) => { ? mathWithUnits(euiTheme.border.width.thick, (x) => x * 2) : euiTheme.border.width.thick; - return highContrastMode !== 'forced' - ? logicalCSS('border-top', `${borderWidth} solid ${color}`) - : // Windows high contrast mode ignores/overrides border colors, which have semantic meaning here. To get around this, we'll use a pseudo element that ignores forced colors - `overflow: hidden; + return highContrastModeStyles(euiThemeContext, { + none: logicalCSS('border-top', `${borderWidth} solid ${color}`), + + // Windows high contrast mode ignores/overrides border colors, which have semantic meaning here. To get around this, we'll use a pseudo element that ignores forced colors + forced: ` + overflow: hidden; &::before { content: ''; @@ -65,8 +71,10 @@ export const euiToastStyles = (euiThemeContext: UseEuiTheme) => { ${logicalCSS('horizontal', 0)} ${logicalCSS('height', borderWidth)} background-color: ${color}; - forced-color-adjust: none; - }`; + ${preventForcedColors(euiThemeContext)} + } + `, + }); }, get primary() { return css(this._getStyles(euiTheme.colors.primary)); diff --git a/packages/eui/src/global_styling/functions/high_contrast.test.ts b/packages/eui/src/global_styling/functions/high_contrast.test.ts new file mode 100644 index 00000000000..046e152582e --- /dev/null +++ b/packages/eui/src/global_styling/functions/high_contrast.test.ts @@ -0,0 +1,165 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { UseEuiTheme } from '../../services'; +import { highContrastModeStyles, preventForcedColors } from './high_contrast'; + +const mockForcedHighContrastMode = { + highContrastMode: 'forced', +} as UseEuiTheme; + +const mockPreferredHighContrastMode = { + highContrastMode: 'preferred', +} as UseEuiTheme; + +const mockRegularContrastMode = { + highContrastMode: false, +} as UseEuiTheme; + +describe('highContrastModeStyles', () => { + describe('no high contrast', () => { + it('returns the passed `none` styles', () => { + expect( + highContrastModeStyles(mockRegularContrastMode, { + none: 'color: red;', + }) + ).toEqual('color: red;'); + expect( + highContrastModeStyles(mockRegularContrastMode, { + none: 'color: red;', + preferred: 'color: black;', + }) + ).toEqual('color: red;'); + expect( + highContrastModeStyles(mockRegularContrastMode, { + none: 'color: red;', + forced: 'forced-color-adjust: none;', + }) + ).toEqual('color: red;'); + expect( + highContrastModeStyles(mockRegularContrastMode, { + none: 'color: red;', + preferred: 'color: black;', + forced: 'forced-color-adjust: none;', + }) + ).toEqual('color: red;'); + }); + + it('returns nothing if no `none` styles were passed', () => { + expect( + highContrastModeStyles(mockRegularContrastMode, { + preferred: 'color: black;', + }) + ).toEqual(''); + expect( + highContrastModeStyles(mockRegularContrastMode, { + forced: 'forced-color-adjust: none;', + }) + ).toEqual(''); + expect( + highContrastModeStyles(mockRegularContrastMode, { + preferred: 'color: black;', + forced: 'forced-color-adjust: none;', + }) + ).toEqual(''); + }); + }); + + describe('preferred high contrast', () => { + it('returns the passed `preferred` styles', () => { + expect( + highContrastModeStyles(mockPreferredHighContrastMode, { + preferred: 'color: black;', + }) + ).toEqual('color: black;'); + expect( + highContrastModeStyles(mockPreferredHighContrastMode, { + none: 'color: red;', + preferred: 'color: black;', + }) + ).toEqual('color: black;'); + }); + + it('ignores `forced` if `preferred` was passed', () => { + expect( + highContrastModeStyles(mockPreferredHighContrastMode, { + none: 'color: red;', + preferred: 'color: black;', + forced: 'forced-color-adjust: none;', + }) + ).toEqual('color: black;'); + }); + + it('falls back to `none` if only `forced` was passed', () => { + expect( + highContrastModeStyles(mockPreferredHighContrastMode, { + none: 'color: red;', + forced: 'forced-color-adjust: none;', + }) + ).toEqual('color: red;'); + }); + + it('returns nothing if no contrast styles were passed', () => { + expect( + highContrastModeStyles(mockPreferredHighContrastMode, { + none: 'color: red;', + }) + ).toEqual(''); + }); + }); + + describe('forced high contrast', () => { + it('returns the passed `forced` styles', () => { + expect( + highContrastModeStyles(mockForcedHighContrastMode, { + forced: 'color: black;', + }) + ).toEqual('color: black;'); + expect( + highContrastModeStyles(mockForcedHighContrastMode, { + none: 'color: red;', + forced: 'color: black;', + }) + ).toEqual('color: black;'); + }); + + it('also returns/concatenates `preferred` styles if passed', () => { + expect( + highContrastModeStyles(mockForcedHighContrastMode, { + preferred: 'background-color: white;', + }) + ).toEqual('background-color: white;'); + expect( + highContrastModeStyles(mockForcedHighContrastMode, { + preferred: 'background-color: white;', + forced: 'color: black;', + }) + ).toEqual('background-color: white;color: black;'); + }); + + it('returns nothing if no contrast styles were passed', () => { + expect( + highContrastModeStyles(mockForcedHighContrastMode, { + none: 'color: red;', + }) + ).toEqual(''); + }); + }); +}); + +describe('preventForcedColors', () => { + it('returns forced-color-adjust CSS when high contrast is being forced', () => { + expect(preventForcedColors(mockForcedHighContrastMode)).toEqual( + 'forced-color-adjust: none;' + ); + }); + + it('returns nothing when highContrastMode is not forced', () => { + expect(preventForcedColors(mockRegularContrastMode)).toEqual(''); + }); +}); diff --git a/packages/eui/src/global_styling/functions/high_contrast.ts b/packages/eui/src/global_styling/functions/high_contrast.ts new file mode 100644 index 00000000000..a4a2a6ca198 --- /dev/null +++ b/packages/eui/src/global_styling/functions/high_contrast.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { UseEuiTheme } from '../../services'; + +// NOTE: These functions are not being published as top-level EUI exports +// until high contrast mode is out of beta. + +/** + * Minor syntactical sugar for conditional high contrast styles. + * Ternaries are otherwise somewhat ugly in css`` template literals, + * and this makes life just a little more beautiful ✨ + */ +export const highContrastModeStyles = ( + euiThemeContext: UseEuiTheme, + options: { + /** Default styles to render (no high contrast mode) */ + none?: string; + /** Styles to render when high contrast mode is preferred or forced */ + preferred?: string; + /** Styles to render when high contrast mode is being forced */ + forced?: string; + } +) => { + const { highContrastMode } = euiThemeContext; + const { + none: defaultStyles = '', + preferred: highContrastStyles = '', + forced: forcedColorsStyles = '', + } = options; + + if (highContrastMode) { + if (highContrastMode === 'forced') { + // Assume preferred high contrast styles should also apply to forced contrast styles + return highContrastStyles.trim() + forcedColorsStyles.trim(); + } + + if (!highContrastStyles && forcedColorsStyles && defaultStyles) { + // If only forced styles were passed, assume we can use default styles for preferred high contrast + return defaultStyles.trim(); + } + + return highContrastStyles.trim(); + } + return defaultStyles.trim(); +}; + +/** + * Small uitility that allows component styles to ignore/override + * forced colors modes (primarily Windows high contrast themes) + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/forced-color-adjust + * + * WARNING: Do *not* use this utility unless: + * 1. Colors/backgrounds are **essential** to the semantic meaning of the UI, + * and users will lose all meaning without them + * 2. Tweaks have been made to existing styles to increase color contrast + * as necessary + */ +export const preventForcedColors = ({ highContrastMode }: UseEuiTheme) => + highContrastMode === 'forced' ? 'forced-color-adjust: none;' : '';