diff --git a/src-docs/src/views/scroll/utility_classes_overflow.js b/src-docs/src/views/scroll/full_height.tsx similarity index 53% rename from src-docs/src/views/scroll/utility_classes_overflow.js rename to src-docs/src/views/scroll/full_height.tsx index be119b65f5f..d0376e1208a 100644 --- a/src-docs/src/views/scroll/utility_classes_overflow.js +++ b/src-docs/src/views/scroll/full_height.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { EuiText, @@ -7,13 +7,18 @@ import { EuiFlexItem, EuiFlexGroup, } from '../../../../src'; -import { UtilityClassesSection } from '../utility_classes/utility_classes_section'; +import { ThemeContext } from '../../components/with_theme'; +import { ThemeExample } from '../theme/_components/_theme_example'; export default () => { + const themeContext = useContext(ThemeContext); + const currentLanguage = themeContext.themeLanguage; + const showSass = currentLanguage.includes('sass'); + return ( <> - @@ -22,19 +27,7 @@ export default () => { parents dimensions. Use it to stretch each nested element until the one that applies scroll.

-

- It applies{' '} - height: 100%; overflow: hidden;{' '} - but also adds flex: 1 1 auto;{' '} - for uses within flex{' '} - containers. -

-
-
Sass mixins
-
- @include euiFullHeight; -
-
+

Works on both flex and non-flex elements.

} example={ @@ -48,7 +41,7 @@ export default () => { @@ -67,7 +60,7 @@ export default () => { @@ -90,15 +83,66 @@ export default () => { className="eui-fullHeight" responsive={false}> + className="eui-yScroll" tabIndex={0} role="region" aria-label=""/> + className="eui-yScroll" tabIndex={0} role="region" aria-label=""/> `} /> + + {!showSass && ( + {'euiFullHeight()'}} + type="function" + description={ + <> +

+ Emotion mixin for adding full height scrolling to a container or + flex child. +

+

+ It applies{' '} + + height: 100%; overflow: hidden; + {' '} + but also adds flex: 1 1 auto;{' '} + for use within flex containers. +

+ + } + snippet="${euiFullHeight()}" + snippetLanguage="emotion" + /> + )} + + {showSass && ( + {'@include euiFullHeight'}} + type="mixin" + description={ + <> +

+ Sass mixin for adding full height scrolling to a container or + flex child. +

+

+ It applies{' '} + + height: 100%; overflow: hidden; + {' '} + but also adds flex: 1 1 auto;{' '} + for uses within flex{' '} + containers. +

+ + } + snippet="@include euiFullHeight;" + snippetLanguage="sass" + /> + )} ); }; diff --git a/src-docs/src/views/scroll/scroll_example.js b/src-docs/src/views/scroll/scroll_example.js index 9ac8eadc3a5..e03db71f831 100644 --- a/src-docs/src/views/scroll/scroll_example.js +++ b/src-docs/src/views/scroll/scroll_example.js @@ -9,9 +9,9 @@ import { } from '../../../../src'; import ScrollBar from './scroll'; -import Utilities from './utility_classes_overflow'; import ScrollX from './scroll_x'; import ScrollY from './scroll_y'; +import FullHeight from './full_height'; export const ScrollExample = { title: 'Scroll', @@ -101,11 +101,7 @@ export const ScrollExample = { title: 'Full height layout', color: 'subdued', wrapText: false, - text: ( - <> - - - ), + text: , }, ], }; diff --git a/src-docs/src/views/scroll/scroll_x.tsx b/src-docs/src/views/scroll/scroll_x.tsx index 349914f6e48..e932a402dfd 100644 --- a/src-docs/src/views/scroll/scroll_x.tsx +++ b/src-docs/src/views/scroll/scroll_x.tsx @@ -84,7 +84,7 @@ export default () => {

To mask the top and bottom of the scrolled content, indicating visually that there is more content below, pass in true to the - second paremeter mask. + second parameter mask.

{"useEuiOverflowScroll('x', true);"} diff --git a/src-docs/src/views/scroll/scroll_y.tsx b/src-docs/src/views/scroll/scroll_y.tsx index 4942934e67b..c022aabfed9 100644 --- a/src-docs/src/views/scroll/scroll_y.tsx +++ b/src-docs/src/views/scroll/scroll_y.tsx @@ -60,7 +60,7 @@ export default () => {

To mask the top and bottom of the scrolled content, indicating visually that there is more content below, pass in true to the - second paremeter mask. + second parameter mask.

{"useEuiOverflowScroll('y', true);"} diff --git a/src/components/breadcrumbs/breadcrumb.styles.ts b/src/components/breadcrumbs/breadcrumb.styles.ts index 845992f287d..c1300c03b07 100644 --- a/src/components/breadcrumbs/breadcrumb.styles.ts +++ b/src/components/breadcrumbs/breadcrumb.styles.ts @@ -81,10 +81,10 @@ export const euiBreadcrumbContentStyles = (euiThemeContext: UseEuiTheme) => { // Types page: css` &:is(a):focus { - ${euiFocusRing(euiTheme, 'inset')}; + ${euiFocusRing(euiThemeContext, 'inset')}; } &:is(button):focus { - ${euiFocusRing(euiTheme, 'center')}; + ${euiFocusRing(euiThemeContext, 'center')}; } `, application: css` @@ -109,7 +109,7 @@ export const euiBreadcrumbContentStyles = (euiThemeContext: UseEuiTheme) => { color: ${euiTheme.colors.link}; :focus { - ${euiFocusRing(euiTheme, 'inset')}; + ${euiFocusRing(euiThemeContext, 'inset')}; :focus-visible { border-radius: ${euiTheme.border.radius.medium}; diff --git a/src/components/image/image_button.styles.ts b/src/components/image/image_button.styles.ts index 219409f9ec2..99e27699164 100644 --- a/src/components/image/image_button.styles.ts +++ b/src/components/image/image_button.styles.ts @@ -51,7 +51,7 @@ export const euiImageButtonStyles = (euiThemeContext: UseEuiTheme) => { } &:focus { - ${euiFocusRing(euiTheme, 'outset')} + ${euiFocusRing(euiThemeContext, 'outset')} } `, fullWidth: css` diff --git a/src/components/link/link.styles.ts b/src/components/link/link.styles.ts index d17b5b6648d..fccd16b75e0 100644 --- a/src/components/link/link.styles.ts +++ b/src/components/link/link.styles.ts @@ -39,7 +39,8 @@ export const euiLinkFocusCSS = (euiTheme: UseEuiTheme['euiTheme']) => { `; }; -export const euiLinkCSS = (euiTheme: UseEuiTheme['euiTheme']) => { +export const euiLinkCSS = (euiThemeContext: UseEuiTheme) => { + const { euiTheme } = euiThemeContext; return ` font-weight: ${euiTheme.font.weight.medium}; text-align: left; @@ -49,16 +50,17 @@ export const euiLinkCSS = (euiTheme: UseEuiTheme['euiTheme']) => { } &:focus { - ${euiFocusRing(euiTheme, 'outset')} + ${euiFocusRing(euiThemeContext, 'outset')} ${euiLinkFocusCSS(euiTheme)} } `; }; -export const euiLinkStyles = ({ euiTheme }: UseEuiTheme) => { +export const euiLinkStyles = (euiThemeContext: UseEuiTheme) => { + const { euiTheme } = euiThemeContext; return { euiLink: css` - ${euiLinkCSS(euiTheme)} + ${euiLinkCSS(euiThemeContext)} user-select: text; &[target='_blank'] { diff --git a/src/components/text/text.styles.ts b/src/components/text/text.styles.ts index e5b08c01a60..2387ff2e3bb 100644 --- a/src/components/text/text.styles.ts +++ b/src/components/text/text.styles.ts @@ -226,7 +226,7 @@ export const euiTextStyles = (euiThemeContext: UseEuiTheme) => { // Style anchors that don't have a class. This prevents overwriting "buttons" // and other stylized elements passed in. a:not([class]) { - ${euiLinkCSS(euiTheme)} + ${euiLinkCSS(euiThemeContext)} } img { diff --git a/src/components/toast/global_toast_list.styles.ts b/src/components/toast/global_toast_list.styles.ts index 8134cc27b7c..8429a1d2173 100644 --- a/src/components/toast/global_toast_list.styles.ts +++ b/src/components/toast/global_toast_list.styles.ts @@ -11,6 +11,7 @@ import { euiBreakpoint, euiScrollBarStyles, logicalCSS, + logicalCSSWithFallback, logicalSizeCSS, } from '../../global_styling'; import { UseEuiTheme } from '../../services'; @@ -34,8 +35,7 @@ export const euiGlobalToastListStyles = (euiThemeContext: UseEuiTheme) => { ${logicalCSS('bottom', 0)}; ${logicalCSS('width', `${euiToastWidth + euiTheme.base * 5}px`)}; /* 2 */ ${logicalCSS('max-height', '100vh')}; /* 1 */ - overflow-y: auto; // Fallback for the 'overflow-inline' logical property, which is not yet supported - ${logicalCSS('overflow-y', 'auto')}; + ${logicalCSSWithFallback('overflow-y', 'auto')}; // Hide the scrollbar entirely scrollbar-width: none; diff --git a/src/global_styling/functions/__snapshots__/logicals.test.ts.snap b/src/global_styling/functions/__snapshots__/logicals.test.ts.snap index 5cb2bec1b29..97b8d3b60da 100644 --- a/src/global_styling/functions/__snapshots__/logicals.test.ts.snap +++ b/src/global_styling/functions/__snapshots__/logicals.test.ts.snap @@ -86,9 +86,9 @@ exports[`logicalCSS mixin returns a string property for each directional propert exports[`logicalCSS mixin returns a string property for each directional property: min-width 1`] = `"min-inline-size: 8px;"`; -exports[`logicalCSS mixin returns a string property for each directional property: overflow-x 1`] = `"overflow-block: 8px;"`; +exports[`logicalCSS mixin returns a string property for each directional property: overflow-x 1`] = `"overflow-inline: 8px;"`; -exports[`logicalCSS mixin returns a string property for each directional property: overflow-y 1`] = `"overflow-inline: 8px;"`; +exports[`logicalCSS mixin returns a string property for each directional property: overflow-y 1`] = `"overflow-block: 8px;"`; exports[`logicalCSS mixin returns a string property for each directional property: padding-bottom 1`] = `"padding-block-end: 8px;"`; @@ -110,6 +110,13 @@ exports[`logicalCSS mixin returns a string property for each directional propert exports[`logicalCSS mixin returns a string property for each directional property: width 1`] = `"inline-size: 8px;"`; +exports[`logicalCSSWithFallback returns both the original property and the logical property 1`] = ` +" + overflow-x: auto; + overflow-inline: auto; +" +`; + exports[`logicalStyle mixin returns an object property for each directional property: border-bottom 1`] = ` Object { "borderBlockEnd": "8px", @@ -370,13 +377,13 @@ Object { exports[`logicalStyle mixin returns an object property for each directional property: overflow-x 1`] = ` Object { - "overflowBlock": "8px", + "overflowInline": "8px", } `; exports[`logicalStyle mixin returns an object property for each directional property: overflow-y 1`] = ` Object { - "overflowInline": "8px", + "overflowBlock": "8px", } `; diff --git a/src/global_styling/functions/logicals.test.ts b/src/global_styling/functions/logicals.test.ts index 535f6274469..dd67fe7f9cc 100644 --- a/src/global_styling/functions/logicals.test.ts +++ b/src/global_styling/functions/logicals.test.ts @@ -11,6 +11,7 @@ import { LOGICAL_PROPERTIES, LOGICAL_TEXT_ALIGNMENT, logicalCSS, + logicalCSSWithFallback, logicalStyle, logicalTextAlignCSS, logicalTextAlignStyle, @@ -28,6 +29,14 @@ describe('logicalCSS mixin returns a string property', () => { }); }); +describe('logicalCSSWithFallback ', () => { + it('returns both the original property and the logical property', () => { + expect( + testCustomHook(() => logicalCSSWithFallback('overflow-x', 'auto')).return + ).toMatchSnapshot(); + }); +}); + describe('logicalStyle mixin returns an object property', () => { describe('for each directional property:', () => { LOGICAL_PROPERTIES.forEach((prop) => { diff --git a/src/global_styling/functions/logicals.ts b/src/global_styling/functions/logicals.ts index 711fc440ca6..b1d5bc0c400 100644 --- a/src/global_styling/functions/logicals.ts +++ b/src/global_styling/functions/logicals.ts @@ -65,8 +65,8 @@ const logicalSize = { }; const logicalOverflow = { - 'overflow-x': 'overflow-block', - 'overflow-y': 'overflow-inline', + 'overflow-x': 'overflow-inline', + 'overflow-y': 'overflow-block', }; const logicalBorders = { @@ -122,6 +122,24 @@ export const logicalCSS = (property: LogicalProperties, value?: any) => { return `${logicals[property]}: ${value};`; }; +/** + * Some logical properties are not yet fully supported by all browsers. + * For those cases, we should use the old property as a fallback for + * browsers missing support, while allowing supporting browsers to use + * the logical properties. + * + * Examples: + * https://caniuse.com/?search=overflow-block + * https://caniuse.com/mdn-css_properties_float_flow_relative_values + */ +export const logicalCSSWithFallback = ( + property: LogicalProperties, + value?: any +) => ` + ${property}: ${value}; + ${logicalCSS(property, value)} +`; + /** * * @param property A string that is a valid CSS logical property diff --git a/src/global_styling/mixins/__snapshots__/_typography.test.ts.snap b/src/global_styling/mixins/__snapshots__/_typography.test.ts.snap index 064d2dc3298..5d3de5e0af1 100644 --- a/src/global_styling/mixins/__snapshots__/_typography.test.ts.snap +++ b/src/global_styling/mixins/__snapshots__/_typography.test.ts.snap @@ -205,7 +205,7 @@ exports[`euiTextBreakWord returns a string of CSS text 1`] = ` exports[`euiTextTruncate allows customizing max-width 1`] = ` " - max-width: 150px; // Ensure that the node has a maximum width after which truncation can occur + max-inline-size: 150px; overflow: hidden !important; text-overflow: ellipsis !important; white-space: nowrap !important; @@ -214,7 +214,7 @@ exports[`euiTextTruncate allows customizing max-width 1`] = ` exports[`euiTextTruncate returns a string of CSS text 1`] = ` " - max-width: 100%; // Ensure that the node has a maximum width after which truncation can occur + max-inline-size: 100%; overflow: hidden !important; text-overflow: ellipsis !important; white-space: nowrap !important; diff --git a/src/global_styling/mixins/_helpers.scss b/src/global_styling/mixins/_helpers.scss index 5d937d609e1..db1c6fbd935 100644 --- a/src/global_styling/mixins/_helpers.scss +++ b/src/global_styling/mixins/_helpers.scss @@ -82,6 +82,15 @@ @include euiOverflowShadow('x'); } +/** + * For quickly applying a full-height element whether using flex or not + */ +@mixin euiFullHeight { + height: 100%; + flex: 1 1 auto; + overflow: hidden; +} + // Hiding elements offscreen to only be read by screen reader // See https://github.com/elastic/eui/pull/5130 and https://github.com/elastic/eui/pull/5152 for more info @mixin euiScreenReaderOnly { diff --git a/src/global_styling/mixins/_helpers.ts b/src/global_styling/mixins/_helpers.ts index cafae90b1e6..46c460ff05f 100644 --- a/src/global_styling/mixins/_helpers.ts +++ b/src/global_styling/mixins/_helpers.ts @@ -9,6 +9,7 @@ import { CSSProperties } from 'react'; import { useEuiTheme, UseEuiTheme } from '../../services/theme'; import { transparentize } from '../../services/color'; +import { logicalCSS, logicalCSSWithFallback } from '../functions'; /** * Set scroll bar appearance on Chrome (and firefox). @@ -54,8 +55,8 @@ export const euiScrollBarStyles = ( return `scrollbar-width: ${width}; &::-webkit-scrollbar { - width: ${scrollBarSize}; - height: ${scrollBarSize}; + ${logicalCSS('width', scrollBarSize)} + ${logicalCSS('height', scrollBarSize)} } &::-webkit-scrollbar-thumb { @@ -127,15 +128,14 @@ const euiOverflowShadowStyles = ( interface _EuiYScroll { height?: CSSProperties['height']; } -// TODO: How do we use Emotion to output the CSS class utilities instead? export const euiYScroll = ( euiTheme: UseEuiTheme, { height }: _EuiYScroll = {} ) => ` ${euiScrollBarStyles(euiTheme)} - height: ${height || '100%'}; - overflow-y: auto; - overflow-x: hidden; + ${logicalCSS('height', height || '100%')} + ${logicalCSSWithFallback('overflow-y', 'auto')} + ${logicalCSSWithFallback('overflow-x', 'hidden')} &:focus { outline: none; /* 1 */ } @@ -159,7 +159,7 @@ export const useEuiYScrollWithShadows = ({ height }: _EuiYScroll = {}) => { export const euiXScroll = (euiTheme: UseEuiTheme) => ` ${euiScrollBarStyles(euiTheme)} - overflow-x: auto; + ${logicalCSSWithFallback('overflow-x', 'auto')} &:focus { outline: none; /* 1 */ } @@ -206,3 +206,12 @@ export const useEuiOverflowScroll = ( const euiTheme = useEuiTheme(); return euiOverflowScroll(euiTheme, { direction, mask }); }; + +/** + * For quickly applying a full-height element whether using flex or not + */ +export const euiFullHeight = () => ` + ${logicalCSS('height', '100%')} + flex: 1 1 auto; + overflow: hidden; +`; diff --git a/src/global_styling/mixins/_states.ts b/src/global_styling/mixins/_states.ts index 744eab0796a..09741801086 100644 --- a/src/global_styling/mixins/_states.ts +++ b/src/global_styling/mixins/_states.ts @@ -24,7 +24,7 @@ export type _EuiFocusRingOffset = * @param color Accepts any CSS color, **Note: only works in -webkit-** */ export const euiFocusRing = ( - euiTheme: UseEuiTheme['euiTheme'], + { euiTheme }: UseEuiTheme, offset: _EuiFocusRingOffset = 'center', options?: { color?: CSSProperties['outlineColor'] } ) => { @@ -66,6 +66,6 @@ export const useEuiFocusRing = ( offset?: _EuiFocusRingOffset, color?: CSSProperties['outlineColor'] ) => { - const { euiTheme } = useEuiTheme(); + const euiTheme = useEuiTheme(); return euiFocusRing(euiTheme, offset, { color }); }; diff --git a/src/global_styling/mixins/_typography.ts b/src/global_styling/mixins/_typography.ts index 372b0fdb46a..db62a90a287 100644 --- a/src/global_styling/mixins/_typography.ts +++ b/src/global_styling/mixins/_typography.ts @@ -14,6 +14,7 @@ import { } from '../functions/typography'; import { useEuiTheme, UseEuiTheme } from '../../services/theme/hooks'; import { _EuiThemeFontScale } from '../variables/typography'; +import { logicalCSS } from '../functions'; export type EuiThemeFontSize = { fontSize: CSSProperties['fontSize']; @@ -57,7 +58,9 @@ export const euiTextBreakWord = () => ` export const euiTextTruncate = ( maxWidth: CSSProperties['maxWidth'] = '100%' ) => ` - max-width: ${maxWidth}; // Ensure that the node has a maximum width after which truncation can occur + ${ + logicalCSS('max-width', maxWidth) // Ensure that the node has a maximum width after which truncation can occur + } overflow: hidden !important; text-overflow: ellipsis !important; white-space: nowrap !important; diff --git a/src/global_styling/reset/global_styles.tsx b/src/global_styling/reset/global_styles.tsx index dbff38e5743..8574ac45ca5 100644 --- a/src/global_styling/reset/global_styles.tsx +++ b/src/global_styling/reset/global_styles.tsx @@ -85,7 +85,7 @@ export const EuiGlobalStyles = ({}: EuiGlobalStylesProps) => { } *:focus { - ${euiFocusRing(euiTheme)} + ${euiFocusRing(euiThemeContext)} } // Dark mode's highlighted doesn't work well so lets just set it the same as our focus background diff --git a/src/global_styling/utility/__snapshots__/utility.test.tsx.snap b/src/global_styling/utility/__snapshots__/utility.test.tsx.snap new file mode 100644 index 00000000000..a233f829e4e --- /dev/null +++ b/src/global_styling/utility/__snapshots__/utility.test.tsx.snap @@ -0,0 +1,350 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`global utility styles generates static global styles 1`] = ` +".euiScreenReaderOnly{ + // Take the element out of the layout + position: absolute; + // Keep it vertically inline + top: auto; + // Chrome requires a left value, and Selenium (used by Kibana's FTR) requires an off-screen position for its .getVisibleText() to not register SR-only text + left: -10000px; + // The element must have a size (for some screen readers) + width: 1px; + height: 1px; + // But reduce the visible size to nothing + clip: rect(0 0 0 0); + clip-path: inset(50%); + // And ensure no overflows occur + overflow: hidden; + // Chrome requires the negative margin to not cause overflows of parent containers + margin: -1px; +;} +.eui-alignBaseline{vertical-align:baseline!important;} +.eui-alignBottom{vertical-align:bottom!important;} +.eui-alignMiddle{vertical-align:middle!important;} +.eui-alignTop{vertical-align:top!important;} +.eui-displayBlock{display:block!important;} +.eui-displayInline{display:inline!important;} +.eui-displayInlineBlock{display:inline-block!important;} +.eui-fullWidth{display:block!important;inline-size: 100% !important;;} +.eui-fullHeight{ + block-size: 100%; + flex: 1 1 auto; + overflow: hidden; +;} +.eui-textCenter{text-align:center!important;} +.eui-textLeft{text-align:start!important;} +.eui-textRight{text-align:end!important;} +.eui-textNoWrap{white-space:nowrap!important;} +.eui-textInheritColor{color:inherit!important;} +.eui-textBreakWord{ + overflow-wrap: break-word !important; // makes sure the long string will wrap and not bust out of the container + word-wrap: break-word !important; // spec says, they are literally just alternate names for each other but some browsers support one and not the other + word-break: break-word; // IE doesn't understand but that's ok +;} +.eui-textBreakAll{overflow-wrap:break-word!important;word-break:break-all!important;} +.eui-textBreakNormal{overflow-wrap:normal!important;word-wrap:normal!important;word-break:normal!important;} +.eui-textTruncate{ + max-inline-size: 100%; + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; +;} +.eui-textNumber{ + font-feature-settings: 'calt' 1, 'kern' 1, 'liga' 1, 'tnum' 1; +;} +.eui-scrollBar{scrollbar-width: thin; + + &::-webkit-scrollbar { + inline-size: 16px; + block-size: 16px; + } + + &::-webkit-scrollbar-thumb { + background-color: rgba(105,112,125,0.5); + background-clip: content-box; + border-radius: 16px; + border: calc(8px * 0.75) solid transparent; + } + + &::-webkit-scrollbar-corner, + &::-webkit-scrollbar-track { + background-color: transparent; + } + + scrollbar-color: rgba(105,112,125,0.5) transparent; + ;} +.eui-yScroll{ + scrollbar-width: thin; + + &::-webkit-scrollbar { + inline-size: 16px; + block-size: 16px; + } + + &::-webkit-scrollbar-thumb { + background-color: rgba(105,112,125,0.5); + background-clip: content-box; + border-radius: 16px; + border: calc(8px * 0.75) solid transparent; + } + + &::-webkit-scrollbar-corner, + &::-webkit-scrollbar-track { + background-color: transparent; + } + + scrollbar-color: rgba(105,112,125,0.5) transparent; + + block-size: 100%; + + overflow-y: auto; + overflow-block: auto; + + + overflow-x: hidden; + overflow-inline: hidden; + + &:focus { + outline: none; /* 1 */ + } +;} +.eui-xScroll{ + scrollbar-width: thin; + + &::-webkit-scrollbar { + inline-size: 16px; + block-size: 16px; + } + + &::-webkit-scrollbar-thumb { + background-color: rgba(105,112,125,0.5); + background-clip: content-box; + border-radius: 16px; + border: calc(8px * 0.75) solid transparent; + } + + &::-webkit-scrollbar-corner, + &::-webkit-scrollbar-track { + background-color: transparent; + } + + scrollbar-color: rgba(105,112,125,0.5) transparent; + + + overflow-x: auto; + overflow-inline: auto; + + &:focus { + outline: none; /* 1 */ + } +;} +.eui-yScrollWithShadows{ + + scrollbar-width: thin; + + &::-webkit-scrollbar { + inline-size: 16px; + block-size: 16px; + } + + &::-webkit-scrollbar-thumb { + background-color: rgba(105,112,125,0.5); + background-clip: content-box; + border-radius: 16px; + border: calc(8px * 0.75) solid transparent; + } + + &::-webkit-scrollbar-corner, + &::-webkit-scrollbar-track { + background-color: transparent; + } + + scrollbar-color: rgba(105,112,125,0.5) transparent; + + block-size: 100%; + + overflow-y: auto; + overflow-block: auto; + + + overflow-x: hidden; + overflow-inline: hidden; + + &:focus { + outline: none; /* 1 */ + } + + mask-image: linear-gradient(to bottom, + rgba(255,0,0,0.1) 0%, + rgb(255,0,0) calc(16px * 0.75 * 1.25) + , + rgb(255,0,0) calc(100% - calc(16px * 0.75 * 1.25)), + rgba(255,0,0,0.1) 100% + ); +;} +.eui-xScrollWithShadows{ + + scrollbar-width: thin; + + &::-webkit-scrollbar { + inline-size: 16px; + block-size: 16px; + } + + &::-webkit-scrollbar-thumb { + background-color: rgba(105,112,125,0.5); + background-clip: content-box; + border-radius: 16px; + border: calc(8px * 0.75) solid transparent; + } + + &::-webkit-scrollbar-corner, + &::-webkit-scrollbar-track { + background-color: transparent; + } + + scrollbar-color: rgba(105,112,125,0.5) transparent; + + + overflow-x: auto; + overflow-inline: auto; + + &:focus { + outline: none; /* 1 */ + } + + mask-image: linear-gradient(to right, + rgba(255,0,0,0.1) 0%, + rgb(255,0,0) calc(16px * 0.75 * 1.25) + , + rgb(255,0,0) calc(100% - calc(16px * 0.75 * 1.25)), + rgba(255,0,0,0.1) 100% + ); +;}[class*='eui-showFor']{display:none!important;} + .eui-hideFor--xl { + @media only screen and (min-width: 1200px) { + display: none !important; + } + } + .eui-showFor--xl { + @media only screen and (min-width: 1200px) { + display: inline !important; + } + } + .eui-showFor--xl--block { + @media only screen and (min-width: 1200px) { + display: block !important; + } + } + .eui-showFor--xl--inlineBlock { + @media only screen and (min-width: 1200px) { + display: inline-block !important; + } + } + .eui-showFor--xl--flex { + @media only screen and (min-width: 1200px) { + display: flex !important; + } + }; + .eui-hideFor--l { + @media only screen and (min-width: 992px) and (max-width: 1199px) { + display: none !important; + } + } + .eui-showFor--l { + @media only screen and (min-width: 992px) and (max-width: 1199px) { + display: inline !important; + } + } + .eui-showFor--l--block { + @media only screen and (min-width: 992px) and (max-width: 1199px) { + display: block !important; + } + } + .eui-showFor--l--inlineBlock { + @media only screen and (min-width: 992px) and (max-width: 1199px) { + display: inline-block !important; + } + } + .eui-showFor--l--flex { + @media only screen and (min-width: 992px) and (max-width: 1199px) { + display: flex !important; + } + }; + .eui-hideFor--m { + @media only screen and (min-width: 768px) and (max-width: 991px) { + display: none !important; + } + } + .eui-showFor--m { + @media only screen and (min-width: 768px) and (max-width: 991px) { + display: inline !important; + } + } + .eui-showFor--m--block { + @media only screen and (min-width: 768px) and (max-width: 991px) { + display: block !important; + } + } + .eui-showFor--m--inlineBlock { + @media only screen and (min-width: 768px) and (max-width: 991px) { + display: inline-block !important; + } + } + .eui-showFor--m--flex { + @media only screen and (min-width: 768px) and (max-width: 991px) { + display: flex !important; + } + }; + .eui-hideFor--s { + @media only screen and (min-width: 575px) and (max-width: 767px) { + display: none !important; + } + } + .eui-showFor--s { + @media only screen and (min-width: 575px) and (max-width: 767px) { + display: inline !important; + } + } + .eui-showFor--s--block { + @media only screen and (min-width: 575px) and (max-width: 767px) { + display: block !important; + } + } + .eui-showFor--s--inlineBlock { + @media only screen and (min-width: 575px) and (max-width: 767px) { + display: inline-block !important; + } + } + .eui-showFor--s--flex { + @media only screen and (min-width: 575px) and (max-width: 767px) { + display: flex !important; + } + }; + .eui-hideFor--xs { + @media only screen and (max-width: 574px) { + display: none !important; + } + } + .eui-showFor--xs { + @media only screen and (max-width: 574px) { + display: inline !important; + } + } + .eui-showFor--xs--block { + @media only screen and (max-width: 574px) { + display: block !important; + } + } + .eui-showFor--xs--inlineBlock { + @media only screen and (max-width: 574px) { + display: inline-block !important; + } + } + .eui-showFor--xs--flex { + @media only screen and (max-width: 574px) { + display: flex !important; + } + };;;label:globalStyles;" +`; diff --git a/src/global_styling/utility/_utility.scss b/src/global_styling/utility/_utility.scss index 26c4d8b44e0..b7cae579552 100644 --- a/src/global_styling/utility/_utility.scss +++ b/src/global_styling/utility/_utility.scss @@ -1,84 +1,6 @@ // This file utilizes !importants on purpose // sass-lint:disable no-important -// Vertical alignment -.eui-alignBaseline { vertical-align: baseline !important; } -.eui-alignBottom { vertical-align: bottom !important; } -.eui-alignMiddle { vertical-align: middle !important; } -.eui-alignTop { vertical-align: top !important; } - -// Display -.eui-displayBlock {display: block !important;} -.eui-displayInline {display: inline !important;} -.eui-displayInlineBlock {display: inline-block !important;} - -.eui-fullWidth { - display: block !important; - width: 100% !important; -} - -// Text -.eui-textCenter {text-align: center !important;} -.eui-textLeft {text-align: left !important;} -.eui-textRight {text-align: right !important;} -.eui-textNoWrap {white-space: nowrap !important;} -.eui-textInheritColor {color: inherit !important;} - -.eui-textBreakWord { - @include euiTextBreakWord; -} - -.eui-textBreakAll { - overflow-wrap: break-word !important; // Fixes FF when dashes are involved #2288 - word-break: break-all !important; -} - -.eui-textBreakNormal { - overflow-wrap: normal !important; - word-wrap: normal !important; - word-break: normal !important; -} - -.eui-textTruncate { - @include euiTextTruncate; -} - -.eui-textNumber { - @include euiNumberFormat; -} - -/** - * Responsive - * - * 1. Be sure to hide the element initially - */ - -[class*='eui-showFor'] { - display: none !important; /* 1 */ -} - -@each $size in $euiBreakpointKeys { - .eui-hideFor--#{$size} { - @include euiBreakpoint($size) { display: none !important; } - } - - .eui-showFor--#{$size} { - @include euiBreakpoint($size) { display: inline !important; } - } - - .eui-showFor--#{$size}--block { - @include euiBreakpoint($size) { display: block !important; } - } - - .eui-showFor--#{$size}--inlineBlock { - @include euiBreakpoint($size) { display: inline-block !important; } - } - - .eui-showFor--#{$size}--flex { - @include euiBreakpoint($size) { display: flex !important; } - } -} - /** * IE doesn't properly wrap groups if it is within a flex-item of a flex-group. * Adding the following styles to the flex-item that contains the wrapping group, will fix IE. @@ -91,52 +13,3 @@ flex-basis: 0%; } } - -/** - * Scroll bar only - */ -.eui-scrollBar { - @include euiScrollBar; -} - -/** - * Overflow scrolling - */ -.eui-yScroll { - @include euiYScroll; -} - -.eui-xScroll { - @include euiXScroll; -} - -/** - * Overflow scrolling with shadows - */ -.eui-yScrollWithShadows { - @include euiYScrollWithShadows; -} - -.eui-xScrollWithShadows { - @include euiXScrollWithShadows; -} - -/** - * Forcing focus ring on non-EUI elements - */ -.eui-isFocusable:focus { - @include euiFocusRing('large'); -} - -/** - * For quickly applying a full-height element whether using flex or not - */ -@mixin euiFullHeight { - height: 100%; - flex: 1 1 auto; - overflow: hidden; -} - -.eui-fullHeight { - @include euiFullHeight; -} diff --git a/src/global_styling/utility/utility.test.tsx b/src/global_styling/utility/utility.test.tsx new file mode 100644 index 00000000000..7a5a1725dce --- /dev/null +++ b/src/global_styling/utility/utility.test.tsx @@ -0,0 +1,25 @@ +/* + * 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 { useEuiTheme } from '../../services'; +import { globalStyles } from './utility'; + +describe('global utility styles', () => { + const useTestHook = () => { + const euiTheme = useEuiTheme(); + return globalStyles(euiTheme); + }; + + it('generates static global styles', () => { + const rawStyles = (testCustomHook(useTestHook) as any).return.styles; + // Make Emotion's minification a little less annoying to read + const globalStyles = rawStyles.replace(/}\.eui-/g, '}\n.eui-'); + expect(globalStyles).toMatchSnapshot(); + }); +}); diff --git a/src/global_styling/utility/utility.tsx b/src/global_styling/utility/utility.tsx index 72d7bf31a7d..b0ba9ce4543 100644 --- a/src/global_styling/utility/utility.tsx +++ b/src/global_styling/utility/utility.tsx @@ -9,11 +9,149 @@ import React from 'react'; import { Global, css } from '@emotion/react'; +import { useEuiTheme, UseEuiTheme } from '../../services/theme/hooks'; import { euiScreenReaderOnly } from '../../components/accessibility/screen_reader_only/screen_reader_only.styles'; +import { + euiFullHeight, + euiTextBreakWord, + euiTextTruncate, + euiNumberFormat, + euiScrollBarStyles, + euiYScroll, + euiXScroll, + euiYScrollWithShadows, + euiXScrollWithShadows, + euiBreakpoint, +} from '../mixins'; +import { logicalCSS } from '../functions'; -const globalStyles = css` - .euiScreenReaderOnly { - ${euiScreenReaderOnly()} - } -`; -export const EuiUtilityClasses = () => ; +export const globalStyles = (euiThemeContext: UseEuiTheme) => { + return css` + // Accessibility + .euiScreenReaderOnly { + ${euiScreenReaderOnly()} + } + + // Vertical alignment + .eui-alignBaseline { + vertical-align: baseline !important; + } + .eui-alignBottom { + vertical-align: bottom !important; + } + .eui-alignMiddle { + vertical-align: middle !important; + } + .eui-alignTop { + vertical-align: top !important; + } + + // Display + .eui-displayBlock { + display: block !important; + } + .eui-displayInline { + display: inline !important; + } + .eui-displayInlineBlock { + display: inline-block !important; + } + + .eui-fullWidth { + display: block !important; + ${logicalCSS('width', '100% !important')} + } + .eui-fullHeight { + ${euiFullHeight()} + } + + // Text + .eui-textCenter { + text-align: center !important; + } + .eui-textLeft { + text-align: start !important; + } + .eui-textRight { + text-align: end !important; + } + .eui-textNoWrap { + white-space: nowrap !important; + } + .eui-textInheritColor { + color: inherit !important; + } + .eui-textBreakWord { + ${euiTextBreakWord()} + } + .eui-textBreakAll { + overflow-wrap: break-word !important; // Fixes FF when dashes are involved #2288 + word-break: break-all !important; + } + .eui-textBreakNormal { + overflow-wrap: normal !important; + word-wrap: normal !important; + word-break: normal !important; + } + .eui-textTruncate { + ${euiTextTruncate()} + } + .eui-textNumber { + ${euiNumberFormat(euiThemeContext)} + } + + // Scroll + .eui-scrollBar { + ${euiScrollBarStyles(euiThemeContext)} + } + .eui-yScroll { + ${euiYScroll(euiThemeContext)} + } + .eui-xScroll { + ${euiXScroll(euiThemeContext)} + } + .eui-yScrollWithShadows { + ${euiYScrollWithShadows(euiThemeContext)} + } + .eui-xScrollWithShadows { + ${euiXScrollWithShadows(euiThemeContext)} + } + + // Responsive + [class*='eui-showFor'] { + display: none !important; // Be sure to hide the element initially + } + ${Object.keys(euiThemeContext.euiTheme.breakpoint).map( + (size) => ` + .eui-hideFor--${size} { + ${euiBreakpoint(euiThemeContext, [size])} { + display: none !important; + } + } + .eui-showFor--${size} { + ${euiBreakpoint(euiThemeContext, [size])} { + display: inline !important; + } + } + .eui-showFor--${size}--block { + ${euiBreakpoint(euiThemeContext, [size])} { + display: block !important; + } + } + .eui-showFor--${size}--inlineBlock { + ${euiBreakpoint(euiThemeContext, [size])} { + display: inline-block !important; + } + } + .eui-showFor--${size}--flex { + ${euiBreakpoint(euiThemeContext, [size])} { + display: flex !important; + } + }` + )} + `; +}; +export const EuiUtilityClasses = () => { + const euiTheme = useEuiTheme(); + return ; +}; diff --git a/upcoming_changelogs/6124.md b/upcoming_changelogs/6124.md new file mode 100644 index 00000000000..9b8923e5181 --- /dev/null +++ b/upcoming_changelogs/6124.md @@ -0,0 +1,5 @@ +**CSS-in-JS conversions** + +- Added `logicalCSSWithFallback()` utility for logical properties without full browser support +- Converted `euiFullHeight()` Sass mixin to Emotion +- Converted all global CSS utility classes to Emotion