From 89c0d555bd6659c244ba04a41feae89bdb7f6cd5 Mon Sep 17 00:00:00 2001 From: Caroline Horn <549577+cchaos@users.noreply.github.com> Date: Tue, 3 May 2022 11:43:12 -0400 Subject: [PATCH] [Emotion] Convert `euiFocusRing()` mixin (#5855) * Commented out some unused (yet) properties and updated the Focus docs section * Make `focus` global token required * Updated ThemeExamples code snippets to scroll horizontally * [EuiSplitPanel] Fix border-radius of nested split panels --- .../accessibility/accessibility_example.js | 47 +------ .../views/accessibility/styles_helpers.tsx | 97 ++++++++++++++ .../theme/_components/_theme_example.tsx | 23 +++- .../src/views/theme/customizing/_focus.js | 106 +++++++--------- .../src/views/theme/customizing/_values.tsx | 119 ++++++++++-------- .../src/views/theme/customizing/values.tsx | 6 + .../panel/split_panel/_split_panel.scss | 6 +- .../__snapshots__/provider.test.tsx.snap | 28 +++++ .../mixins/__snapshots__/_states.test.ts.snap | 69 ++++++++++ src/global_styling/mixins/_states.test.ts | 40 ++++++ src/global_styling/mixins/_states.ts | 73 +++++++++++ src/global_styling/mixins/index.ts | 1 + src/global_styling/reset/global_styles.tsx | 50 ++------ src/global_styling/variables/states.ts | 22 ++-- src/services/theme/types.ts | 2 +- .../global_styling/variables/_states.ts | 29 ++--- src/themes/amsterdam/theme.ts | 2 + upcoming_changelogs/5855.md | 7 ++ 18 files changed, 493 insertions(+), 234 deletions(-) create mode 100644 src-docs/src/views/accessibility/styles_helpers.tsx create mode 100644 src/global_styling/mixins/__snapshots__/_states.test.ts.snap create mode 100644 src/global_styling/mixins/_states.test.ts create mode 100644 src/global_styling/mixins/_states.ts create mode 100644 upcoming_changelogs/5855.md diff --git a/src-docs/src/views/accessibility/accessibility_example.js b/src-docs/src/views/accessibility/accessibility_example.js index 21f8f558d8c..095b006f69f 100644 --- a/src-docs/src/views/accessibility/accessibility_example.js +++ b/src-docs/src/views/accessibility/accessibility_example.js @@ -1,5 +1,4 @@ import React from 'react'; -import { css } from '@emotion/react'; import { GuideSectionTypes } from '../../components'; @@ -11,16 +10,13 @@ import { EuiScreenReaderLive, EuiScreenReaderOnly, EuiSpacer, - euiScreenReaderOnlyStyles, - EuiText, } from '../../../../src'; -import { ThemeExample } from '../theme/_components/_theme_example'; - import ScreenReaderLive from './screen_reader_live'; import ScreenReaderOnly from './screen_reader'; import ScreenReaderFocus from './screen_reader_focus'; import SkipLink from './skip_link'; +import StylesHelpers from './styles_helpers'; const screenReaderLiveSource = require('!!raw-loader!./screen_reader_live'); const screenReaderOnlySource = require('!!raw-loader!./screen_reader'); @@ -193,46 +189,7 @@ export const AccessibilityExample = { { title: 'Styles helpers', wrapText: false, - text: ( - <> - .euiScreenReaderOnly} - description={ -

- This utility class allows you to apply the screen reader only - CSS styles directly to your component. -

- } - example={ - -

The next paragraph is hidden except for screen readers.

-

- I am hidden except for screen readers -

-
- } - snippet={'

'} - /> - euiScreenReaderOnlyStyles()} - description={ -

- This function allows you to apply the screen reader only CSS - styles directly to your component. -

- } - example={ - -

The next paragraph is hidden except for screen readers.

-

- I am hidden except for screen readers -

-
- } - snippet={'

'} - /> - - ), + text: , }, ], }; diff --git a/src-docs/src/views/accessibility/styles_helpers.tsx b/src-docs/src/views/accessibility/styles_helpers.tsx new file mode 100644 index 00000000000..75841b9e8bb --- /dev/null +++ b/src-docs/src/views/accessibility/styles_helpers.tsx @@ -0,0 +1,97 @@ +import { css } from '@emotion/react'; +import React from 'react'; + +import { + EuiCode, + euiScreenReaderOnlyStyles, + EuiText, + useEuiFocusRing, +} from '../../../../src'; +import { useEuiTheme } from '../../../../src/services'; +import { ThemeExample } from '../theme/_components/_theme_example'; + +export default () => { + const { euiTheme } = useEuiTheme(); + + return ( + <> + .euiScreenReaderOnly} + description={ +

+ This utility class allows you to apply the screen reader only CSS + styles directly to your component. +

+ } + example={ + +

The next paragraph is hidden except for screen readers.

+

+ I am hidden except for screen readers +

+
+ } + snippet={'

'} + /> + euiScreenReaderOnlyStyles()} + description={ +

+ This function allows you to apply the screen reader only CSS styles + directly to your component. +

+ } + example={ + +

The next paragraph is hidden except for screen readers.

+

+ I am hidden except for screen readers +

+
+ } + snippet={'

'} + /> + useEuiFocusRing(offset?, color?)} + description={ +

+ By default, all interactable elements will inherit the{' '} + outline property from the reset file. However, + some instances require adjustment to the offset{' '} + and color of this outline. This helper function + allows that customization of the focus outline. +

+ } + props={`offset: 'inset' | 'outset' | 'center' | CSSProperties['outlineOffset']; + +color: CSSProperties['outlineColor'];`} + example={ + +

+ +

+

+ +

+
+ } + snippetLanguage="emotion" + snippet={`&:focus { + \${useEuiFocusRing('outset', euiTheme.colors.primary)} + }`} + /> + + ); +}; diff --git a/src-docs/src/views/theme/_components/_theme_example.tsx b/src-docs/src/views/theme/_components/_theme_example.tsx index 76eefe4465c..77c4bb534a7 100644 --- a/src-docs/src/views/theme/_components/_theme_example.tsx +++ b/src-docs/src/views/theme/_components/_theme_example.tsx @@ -25,6 +25,7 @@ export type ThemeExample = { examplePanel?: _EuiSplitPanelInnerProps; snippet?: GuideSectionExample['tabContent']; snippetLanguage?: EuiCodeBlockProps['language']; + props?: ReactNode; provider?: { property?: string; type?: string; @@ -39,6 +40,7 @@ export const ThemeExample: FunctionComponent = ({ examplePanel, snippet, snippetLanguage = 'jsx', + props, }) => { const { euiTheme } = useEuiTheme(); const finalSnippet = @@ -71,25 +73,38 @@ export const ThemeExample: FunctionComponent = ({ {description} + {props && ( + <> + + + {props} + + + )} {(example || snippet) && ( - + {example && ( {example} )} - + {finalSnippet && ( { const { euiTheme } = useEuiTheme(); const focus = euiTheme.focus; - const focusProps = getPropsFromComponent(EuiThemeFocus); - const updateFocus = (property, value) => { - onThemeUpdate({ - focus: { - [property]: value, - }, - }); - }; + const [focusClone, updateFocus] = useDebouncedUpdate({ + property: 'focus', + value: focus, + onUpdate: onThemeUpdate, + }); - const style = css` - width: ${euiTheme.size.xl}; - height: ${euiTheme.size.xl}; - border-radius: ${euiTheme.border.radius.small}; - `; + const focusProps = getPropsFromComponent(EuiThemeFocus); return (
- +

Focus

-
- - - - + + + +

+ _EuiThemeFocus +

+
+ +

These are general properties that apply to the focus state of interactable components. Some components have their own specific implementation, but most use these variables.

- } - themeValues={Object.keys(focus).map((prop) => { - const isColor = prop.toLowerCase().includes('color'); - if (prop === 'outline') { - return ( - - - - {`${JSON.stringify( - focus[prop] - ).replace(/[{}"]/g, '')};`} - - ); - } +
+ + + + {Object.keys(focusProps).map((prop) => { return ( - - updateFocus(prop, value)} - example={ - isColor ? ( - - ) : undefined - } - colorProps={ - isColor ? { showAlpha: true, format: 'rgba' } : undefined - } - /> - + updateFocus(prop, value)} + forceUpdateType="string" + example={null} + numberProps={{ + style: { width: 140 }, + }} + /> ); })} - /> +
); }; diff --git a/src-docs/src/views/theme/customizing/_values.tsx b/src-docs/src/views/theme/customizing/_values.tsx index 857ad1acc47..39b1394c8a2 100644 --- a/src-docs/src/views/theme/customizing/_values.tsx +++ b/src-docs/src/views/theme/customizing/_values.tsx @@ -44,6 +44,7 @@ type ThemeValue = { numberProps?: EuiFieldNumberProps; stringProps?: EuiFieldTextProps; colorProps?: Partial; + forceUpdateType?: 'string' | 'number' | 'color'; }; export const ThemeValue: FunctionComponent = ({ @@ -58,6 +59,7 @@ export const ThemeValue: FunctionComponent = ({ numberProps, stringProps, colorProps, + forceUpdateType, }) => { const { euiTheme } = useEuiTheme(); @@ -87,7 +89,10 @@ export const ThemeValue: FunctionComponent = ({ debouncedOnUpdate(hex, isValid); }; let exampleRender; - if (property === 'colors' || name.toLowerCase().includes('color')) { + if ( + example !== null && + (property === 'colors' || name.toLowerCase().includes('color')) + ) { exampleRender = ( @@ -120,57 +125,69 @@ export const ThemeValue: FunctionComponent = ({ descriptionRender = <>{getDescription(type)}; } - let valueRender; - if ( - (property === 'colors' || name.toLowerCase().includes('color')) && - onUpdate - ) { - valueRender = ( - - { + if (!onUpdate) { + return ( + + {value} + + ); + } + + let updateType = forceUpdateType; + if ( + !updateType && + (property === 'colors' || name.toLowerCase().includes('color')) + ) { + updateType = 'color'; + } else if (!updateType && typeof value === 'number') { + updateType = 'number'; + } else if ( + !updateType && + property !== 'colors' && + !name.toLowerCase().includes('color') && + typeof value === 'string' + ) { + updateType = 'string'; + } + + if (updateType === 'color') { + return ( + + + + ); + } else if (updateType === 'number') { + return ( + onUpdate(Number(e.target.value))} + style={{ width: 64 }} + {...numberProps} /> - - ); - } else if (typeof value === 'number' && onUpdate) { - valueRender = ( - onUpdate(Number(e.target.value))} - style={{ width: 64 }} - {...numberProps} - /> - ); - } else if ( - property !== 'colors' && - !name.toLowerCase().includes('color') && - typeof value === 'string' && - onUpdate - ) { - valueRender = ( - onUpdate(e.target.value)} - style={{ width: 120 }} - {...stringProps} - /> - ); - } else { - valueRender = ( - - {value} - - ); - } + ); + } else if (updateType === 'string') { + return ( + onUpdate(e.target.value)} + style={{ width: 120 }} + {...stringProps} + /> + ); + } + }; name = property ? `${property}.${name}` : name; @@ -193,7 +210,7 @@ export const ThemeValue: FunctionComponent = ({ - {valueRender} + {valueRender()} ); }; diff --git a/src-docs/src/views/theme/customizing/values.tsx b/src-docs/src/views/theme/customizing/values.tsx index a3251356c8b..eae00900f79 100644 --- a/src-docs/src/views/theme/customizing/values.tsx +++ b/src-docs/src/views/theme/customizing/values.tsx @@ -39,6 +39,8 @@ import Animation from './_animation'; import Breakpoints from './_breakpoints'; // @ts-ignore Importing from JS import Levels from './_levels'; +// @ts-ignore Importing from JS +import Focus from './_focus'; import Sass from './_sass'; @@ -116,6 +118,10 @@ export default () => { + + + + )} diff --git a/src/components/panel/split_panel/_split_panel.scss b/src/components/panel/split_panel/_split_panel.scss index 3a8cec7a0fd..88d84f1ee82 100644 --- a/src/components/panel/split_panel/_split_panel.scss +++ b/src/components/panel/split_panel/_split_panel.scss @@ -11,8 +11,8 @@ } @each $modifier, $amount in $euiPanelBorderRadiusModifiers { - &.euiSplitPanel-isResponsive.euiPanel--#{$modifier} .euiSplitPanel__inner, - &.euiPanel--#{$modifier} .euiSplitPanel__inner { + &.euiSplitPanel-isResponsive.euiPanel--#{$modifier} > .euiSplitPanel__inner, + &.euiPanel--#{$modifier} > .euiSplitPanel__inner { &:first-child { border-radius: ($amount - 1) ($amount - 1) 0 0; } @@ -32,7 +32,7 @@ } @each $modifier, $amount in $euiPanelBorderRadiusModifiers { - &.euiPanel--#{$modifier} .euiSplitPanel__inner { + &.euiPanel--#{$modifier} > .euiSplitPanel__inner { &:first-child { border-radius: ($amount - 1) 0 0 ($amount - 1); } diff --git a/src/components/provider/__snapshots__/provider.test.tsx.snap b/src/components/provider/__snapshots__/provider.test.tsx.snap index 1ba6d0a86b3..7a823801e4a 100644 --- a/src/components/provider/__snapshots__/provider.test.tsx.snap +++ b/src/components/provider/__snapshots__/provider.test.tsx.snap @@ -224,6 +224,13 @@ exports[`EuiProvider applying modifications propagates \`modify\` 1`] = ` "ghost": "#FFF", "ink": "#000", }, + "focus": Object { + "color": "currentColor", + "width": Computed { + "computer": [Function], + "dependencies": Array [], + }, + }, "font": Object { "baseline": Computed { "computer": [Function], @@ -533,6 +540,13 @@ exports[`EuiProvider changing color modes propagates \`colorMode\` 1`] = ` "ghost": "#FFF", "ink": "#000", }, + "focus": Object { + "color": "currentColor", + "width": Computed { + "computer": [Function], + "dependencies": Array [], + }, + }, "font": Object { "baseline": Computed { "computer": [Function], @@ -841,6 +855,13 @@ exports[`EuiProvider is rendered 1`] = ` "ghost": "#FFF", "ink": "#000", }, + "focus": Object { + "color": "currentColor", + "width": Computed { + "computer": [Function], + "dependencies": Array [], + }, + }, "font": Object { "baseline": Computed { "computer": [Function], @@ -1170,6 +1191,13 @@ exports[`EuiProvider providing an @emotion cache config applies the cache to glo "ghost": "#FFF", "ink": "#000", }, + "focus": Object { + "color": "currentColor", + "width": Computed { + "computer": [Function], + "dependencies": Array [], + }, + }, "font": Object { "baseline": Computed { "computer": [Function], diff --git a/src/global_styling/mixins/__snapshots__/_states.test.ts.snap b/src/global_styling/mixins/__snapshots__/_states.test.ts.snap new file mode 100644 index 00000000000..80065bc3b6d --- /dev/null +++ b/src/global_styling/mixins/__snapshots__/_states.test.ts.snap @@ -0,0 +1,69 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`useEuiFocusRing hook returns a string for any color: blue 1`] = ` +" + outline: 2px solid blue; + outline-offset: 2px; + + // 👀 Chrome respects :focus-visible and allows coloring the \`auto\` style + &:focus-visible { + outline-style: auto; + } + + // 🙅‍♀️ But Chrome also needs to have the outline forcefully removed from regular \`:focus\` state + &:not(:focus-visible) { + outline: none; + } + " +`; + +exports[`useEuiFocusRing hook returns a string for each offset: 16px 1`] = ` +" + outline: 2px solid currentColor; + outline-offset: 16px; + + // 👀 Chrome respects :focus-visible and allows coloring the \`auto\` style + &:focus-visible { + outline-style: auto; + } + + // 🙅‍♀️ But Chrome also needs to have the outline forcefully removed from regular \`:focus\` state + &:not(:focus-visible) { + outline: none; + } + " +`; + +exports[`useEuiFocusRing hook returns a string for each offset: inset 1`] = ` +" + outline: 2px solid currentColor; + outline-offset: -2px; + + // 👀 Chrome respects :focus-visible and allows coloring the \`auto\` style + &:focus-visible { + outline-style: auto; + } + + // 🙅‍♀️ But Chrome also needs to have the outline forcefully removed from regular \`:focus\` state + &:not(:focus-visible) { + outline: none; + } + " +`; + +exports[`useEuiFocusRing hook returns a string for each offset: outset 1`] = ` +" + outline: 2px solid currentColor; + outline-offset: 2px; + + // 👀 Chrome respects :focus-visible and allows coloring the \`auto\` style + &:focus-visible { + outline-style: auto; + } + + // 🙅‍♀️ But Chrome also needs to have the outline forcefully removed from regular \`:focus\` state + &:not(:focus-visible) { + outline: none; + } + " +`; diff --git a/src/global_styling/mixins/_states.test.ts b/src/global_styling/mixins/_states.test.ts new file mode 100644 index 00000000000..53f81f0d677 --- /dev/null +++ b/src/global_styling/mixins/_states.test.ts @@ -0,0 +1,40 @@ +/* + * 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 { testCustomHook } from '../../test/internal'; +import { useEuiFocusRing } from './_states'; + +describe('useEuiFocusRing hook returns a string', () => { + describe('for each offset:', () => { + it('inset', () => { + expect( + testCustomHook(() => useEuiFocusRing('inset')).return + ).toMatchSnapshot(); + }); + + it('outset', () => { + expect( + testCustomHook(() => useEuiFocusRing('outset')).return + ).toMatchSnapshot(); + }); + + it('16px', () => { + expect( + testCustomHook(() => useEuiFocusRing('16px')).return + ).toMatchSnapshot(); + }); + }); + + describe('for any color:', () => { + it('blue', () => { + expect( + testCustomHook(() => useEuiFocusRing('outset', 'blue')).return + ).toMatchSnapshot(); + }); + }); +}); diff --git a/src/global_styling/mixins/_states.ts b/src/global_styling/mixins/_states.ts new file mode 100644 index 00000000000..d44ee4053cd --- /dev/null +++ b/src/global_styling/mixins/_states.ts @@ -0,0 +1,73 @@ +/* + * 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 { CSSProperties } from 'react'; +import { useEuiTheme, UseEuiTheme } from '../../services'; + +export type _EuiFocusRingOffset = + | 'inset' + | 'outset' + | 'center' + | CSSProperties['outlineOffset']; + +/** + * It is best practice to utilize the browser's default `outline` property for handling focus rings. + * However, some components need to be forced to have the same behavior, or adjust the display. + * This function re-applies the same default outline with a couple parameters + * @param euiTheme UseEuiTheme.euiTheme + * @param offset Accepts a specific measurement or 'inset', 'outset' or 'center' to adjust outline position + * @param color Accepts any CSS color, **Note: only works in -webkit-** + */ +export const euiFocusRing = ( + euiTheme: UseEuiTheme['euiTheme'], + offset: _EuiFocusRingOffset = 'center', + color?: CSSProperties['outlineColor'] +) => { + // Width is enforced as a constant at the global theme layer + const outlineWidth = euiTheme.focus.width; + const outlineColor = color || euiTheme.focus.color; + + let outlineOffset = offset; + if (offset === 'inset') { + outlineOffset = `-${outlineWidth}`; + } else if (offset === 'outset') { + outlineOffset = `${outlineWidth}`; + } else if (offset === 'center') { + outlineOffset = `calc(${outlineWidth} / -2);`; + } + + // This function utilizes `focus-visible` to turn on focus outlines. + // But this is browser-dependend: + // 👉 Safari and Firefox innately respect only showing the outline with keyboard only + // 💔 But they don't allow coloring of the 'auto'/default outline, so contrast is no good in dark mode. + // 👉 For these browsers we use the solid type in order to match with `currentColor. + // 😦 Which does means the outline will be square + return ` + outline: ${outlineWidth} solid ${outlineColor}; + outline-offset: ${outlineOffset}; + + // 👀 Chrome respects :focus-visible and allows coloring the \`auto\` style + &:focus-visible { + outline-style: auto; + } + + // 🙅‍♀️ But Chrome also needs to have the outline forcefully removed from regular \`:focus\` state + &:not(:focus-visible) { + outline: none; + } + `; +}; + +// Hook version +export const useEuiFocusRing = ( + offset?: _EuiFocusRingOffset, + color?: CSSProperties['outlineColor'] +) => { + const { euiTheme } = useEuiTheme(); + return euiFocusRing(euiTheme, offset, color); +}; diff --git a/src/global_styling/mixins/index.ts b/src/global_styling/mixins/index.ts index 7b844ee6611..7089d8cd5aa 100644 --- a/src/global_styling/mixins/index.ts +++ b/src/global_styling/mixins/index.ts @@ -7,4 +7,5 @@ */ export * from './_helpers'; +export * from './_states'; export * from './_typography'; diff --git a/src/global_styling/reset/global_styles.tsx b/src/global_styling/reset/global_styles.tsx index 086ff6ffaac..a8950c5ef92 100644 --- a/src/global_styling/reset/global_styles.tsx +++ b/src/global_styling/reset/global_styles.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { Global, css } from '@emotion/react'; -import { euiScrollBarStyles } from '../mixins'; +import { euiFocusRing, euiScrollBarStyles } from '../mixins'; import { shade, tint, transparentize } from '../../services/color'; import { useEuiTheme } from '../../services/theme'; import { resetStyles as reset } from './reset'; @@ -17,7 +17,7 @@ export interface EuiGlobalStylesProps {} export const EuiGlobalStyles = ({}: EuiGlobalStylesProps) => { const { euiTheme, colorMode } = useEuiTheme(); - const { base, border, colors, font } = euiTheme; + const { base, colors, font } = euiTheme; /** * Declaring the top level scrollbar colors to match the theme also requires setting the sizes on Chrome @@ -42,40 +42,6 @@ export const EuiGlobalStyles = ({}: EuiGlobalStylesProps) => { font-weight: ${font.weight[font.body.weight]}; `; - /** - * Outline/Focus state resets - */ - const focusReset = () => { - // The latest theme utilizes `focus-visible` to turn on focus outlines. - // But this is browser-dependend: - // 👉 Safari and Firefox innately respect only showing the outline with keyboard only - // 💔 But they don't allow coloring of the 'auto'/default outline, so contrast is no good in dark mode. - // 👉 For these browsers we use the solid type in order to match with \`currentColor\`. - // 😦 Which does means the outline will be square - return `*:focus { - outline: currentColor solid ${border.width.thick}; - outline-offset: calc(-(${border.width.thick} / 2) * -1); - - // 👀 Chrome respects :focus-visible and allows coloring the \`auto\` style - &:focus-visible { - outline-style: auto; - } - - // 🙅‍♀️ But Chrome also needs to have the outline forcefully removed from regular \`:focus\` state - &:not(:focus-visible) { - outline: none; - } - } - - // Dark mode's highlighted doesn't work well so lets just set it the same as our focus background - ::selection { - background: ${transparentize( - colors.primary, - colorMode === 'LIGHT' ? 0.1 : 0.2 - )} - }`; - }; - /** * Final styles */ @@ -117,7 +83,17 @@ export const EuiGlobalStyles = ({}: EuiGlobalStylesProps) => { font-weight: ${font.weight.bold}; } - ${focusReset()} + *:focus { + ${euiFocusRing(euiTheme)} + } + + // Dark mode's highlighted doesn't work well so lets just set it the same as our focus background + ::selection { + background: ${transparentize( + colors.primary, + colorMode === 'LIGHT' ? 0.1 : 0.2 + )}; + } a { color: ${colors.primaryText}; diff --git a/src/global_styling/variables/states.ts b/src/global_styling/variables/states.ts index a55532dd2a8..997ece80672 100644 --- a/src/global_styling/variables/states.ts +++ b/src/global_styling/variables/states.ts @@ -11,7 +11,7 @@ import { CSSProperties } from 'react'; /** * NOTE: These were quick conversions of their Sass counterparts. - * They have yet to be used/tested. + * The commented out keys have not been established as necessary yet. */ export interface _EuiThemeFocusOutline { @@ -23,27 +23,23 @@ export interface _EuiThemeFocusOutline { export interface _EuiThemeFocus { /** - * Color is used deterministically by the legacy theme, and as fallback for Amsterdam + * Default color of the focus ring, some components may override this property */ color: ColorModeSwitch; /** - * Used to transprentize any color at certain values + * Thickness of the outline */ - transparency: ColorModeSwitch; - /** - * Default color plus transparency - */ - backgroundColor: ColorModeSwitch; + width: CSSProperties['borderWidth']; /** - * Width is the thickness of the outline or faux ring + * Used to transparentize any color at certain values */ - width: CSSProperties['borderWidth']; + // transparency: ColorModeSwitch; /** - * Larger thickness of the outline for larger components + * Default color plus transparency */ - widthLarge: CSSProperties['borderWidth']; + // backgroundColor: ColorModeSwitch; /** * Using `outline` is new for Amsterdam but is set to `none` in legacy theme */ - outline: _EuiThemeFocusOutline; + // outline: _EuiThemeFocusOutline; } diff --git a/src/services/theme/types.ts b/src/services/theme/types.ts index 5e4709b5fef..554b233f9ed 100644 --- a/src/services/theme/types.ts +++ b/src/services/theme/types.ts @@ -50,7 +50,7 @@ export type EuiThemeShape = { size: _EuiThemeSizes; font: _EuiThemeFont; border: _EuiThemeBorder; - focus?: _EuiThemeFocus; + focus: _EuiThemeFocus; animation: _EuiThemeAnimation; breakpoint: _EuiThemeBreakpoints; levels: _EuiThemeLevels; diff --git a/src/themes/amsterdam/global_styling/variables/_states.ts b/src/themes/amsterdam/global_styling/variables/_states.ts index 761e23a9353..e50564e94fa 100644 --- a/src/themes/amsterdam/global_styling/variables/_states.ts +++ b/src/themes/amsterdam/global_styling/variables/_states.ts @@ -6,29 +6,26 @@ * Side Public License, v 1. */ -import { computed } from '../../../../services/theme/utils'; -import { transparentize } from '../../../../services/color'; -import { _EuiThemeFocus } from '../../../../global_styling/variables/states'; -import { sizeToPixel } from '../../../../global_styling/functions/size'; - /** * NOTE: These were quick conversions of their Sass counterparts. - * They have yet to be used/tested. + * The commented out keys have not been established as necessary yet. */ +import { computed } from '../../../../services/theme/utils'; +import { _EuiThemeFocus } from '../../../../global_styling/variables/states'; +import { sizeToPixel } from '../../../../global_styling/functions/size'; + export const focus: _EuiThemeFocus = { color: 'currentColor', - transparency: { LIGHT: 0.9, DARK: 0.7 }, - backgroundColor: computed(({ colors, focus }) => - transparentize(colors.primary, focus!.transparency) - ), - - // Sizing - widthLarge: computed(sizeToPixel(0.25)), width: computed(sizeToPixel(0.125)), + // transparency: { LIGHT: 0.9, DARK: 0.7 }, + // backgroundColor: computed(({ colors, focus }) => + // transparentize(colors.primary, focus!.transparency) + // ), + // Outline - outline: { - outline: computed(({ focus }) => `${focus!.width} solid ${focus!.color}`), - }, + // outline: { + // outline: computed(({ focus }) => `${focus!.width} solid ${focus!.color}`), + // }, }; diff --git a/src/themes/amsterdam/theme.ts b/src/themes/amsterdam/theme.ts index 482025834aa..515918ad409 100644 --- a/src/themes/amsterdam/theme.ts +++ b/src/themes/amsterdam/theme.ts @@ -16,6 +16,7 @@ import { base, size } from './global_styling/variables/_size'; import { border } from './global_styling/variables/_borders'; import { levels } from './global_styling/variables/_levels'; import { font } from './global_styling/variables/_typography'; +import { focus } from './global_styling/variables/_states'; export const AMSTERDAM_NAME_KEY = 'EUI_THEME_AMSTERDAM'; @@ -28,6 +29,7 @@ export const euiThemeAmsterdam: EuiThemeShape = { animation, breakpoint, levels, + focus, }; export const EuiThemeAmsterdam = buildTheme( diff --git a/upcoming_changelogs/5855.md b/upcoming_changelogs/5855.md new file mode 100644 index 00000000000..4bd00aee9aa --- /dev/null +++ b/upcoming_changelogs/5855.md @@ -0,0 +1,7 @@ +- Added `focus` token to global `EuiTheme` +- Added `euiFocusRing()` and `useEuiFocusRing()` function/hook for customizing focus outline + +**Bug fixes** + +- Fixed border-radius of nested `EuiSplitPanel`s +- Fixed `offset` of global focus `outline`