From d1d6bbaae182ea9f5fd66c1dfcbec95ff7f75fd2 Mon Sep 17 00:00:00 2001 From: Davey Holler Date: Thu, 13 Oct 2022 13:17:40 -0700 Subject: [PATCH 01/17] WIP Tabs emotion conversion --- src/components/tabs/_index.scss | 1 - src/components/tabs/tab.styles.ts | 117 ++++++++++++++++++++++++++++++ src/components/tabs/tab.tsx | 41 +++++++++-- src/components/tabs/tabs.tsx | 15 +++- 4 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 src/components/tabs/tab.styles.ts diff --git a/src/components/tabs/_index.scss b/src/components/tabs/_index.scss index 8a42015a156..e69de29bb2d 100644 --- a/src/components/tabs/_index.scss +++ b/src/components/tabs/_index.scss @@ -1 +0,0 @@ -@import 'tabs'; diff --git a/src/components/tabs/tab.styles.ts b/src/components/tabs/tab.styles.ts new file mode 100644 index 00000000000..98292937ca0 --- /dev/null +++ b/src/components/tabs/tab.styles.ts @@ -0,0 +1,117 @@ +/* + * 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 { css } from '@emotion/react'; +import { euiFontSize, logicalCSS } from '../../global_styling'; +import { UseEuiTheme } from '../../services'; +import { EuiThemeComputed } from '../../services/theme/types'; + +const selectedStyles = (euiTheme: EuiThemeComputed, isDisabled: boolean) => { + const selectedColor = isDisabled + ? euiTheme.colors.disabledText + : euiTheme.colors.primaryText; + return css` + box-shadow: inset 0 calc(${euiTheme.border.thick} - 1) 0 ${selectedColor}; + `; +}; + +export const euiTabsStyles = ({ euiTheme }: UseEuiTheme) => { + return { + euiTabs: css` + display: flex; + ${logicalCSS('max-width', '100%')}; + ${logicalCSS('overflow-x', 'auto')}; + ${logicalCSS('overflow-y', 'hidden')}; + position: relative; + flex-shrink: 0; + `, + bottomBorder: css` + box-shadow: inset 0 calc(${euiTheme.border.width.thin} * -1) 0 + ${euiTheme.border.color}; + `, + }; +}; + +export const euiTabsExpandedStyles = () => { + return { + euiTabsExpanded: css` + flex-basis: 0%; + flex-grow: 1; + justify-content: center; + `, + }; +}; + +export const euiTabStyles = ( + euiThemeContext: UseEuiTheme, + isDisabled: boolean +) => { + const { euiTheme } = euiThemeContext; + return { + euiTab: css` + cursor: pointer; + flex-direction: row; + align-items: center; + font-weight: ${euiTheme.font.weight.semiBold}; + + &:focus { + background-color: ${euiTheme.colors.lightestShade}; + outline-offset: -${euiTheme.focus.width}; + } + `, + + euiTabContentBase: css` + color: ${euiTheme.colors.text}; + `, + + euiTabContentSelected: css` + color: ${euiTheme.colors.primaryText}; + `, + + euiTabContentDisabled: css` + color: ${euiTheme.colors.disabledText}; + `, + + size_s: css` + padding: ${euiTheme.size.s}; + font-size: ${euiFontSize(euiThemeContext, 's').fontSize}; + `, + + // DEFAULT + size_m: css` + padding: ${euiTheme.size.m} ${euiTheme.size.base}; + font-size: ${euiFontSize(euiThemeContext, 'm').fontSize}; + `, + + size_l: css` + padding: ${euiTheme.size.m} ${euiTheme.size.base}; + font-size: ${euiFontSize(euiThemeContext, 'm').fontSize}; + `, + + size_xl: css` + padding: ${euiTheme.size.s} ${euiTheme.size.l}; + font-size: ${euiFontSize(euiThemeContext, 'l').fontSize}; + line-height: calc(${euiFontSize(euiThemeContext, 'l').lineHeight} * 4.5); + ${logicalCSS('height', `calc(${euiTheme.size.base} * 4.5`)} + `, + + prepend: css` + ${logicalCSS('margin-right', euiTheme.size.s)}; + color: ${euiTheme.colors[isDisabled ? 'disabledText' : 'text']}; + `, + + append: css` + ${logicalCSS('margin-left', euiTheme.size.s)}; + color: ${euiTheme.colors[isDisabled ? 'disabledText' : 'text']}; + `, + + isSelected: css` + ${selectedStyles(euiTheme, isDisabled)}; + `, + }; +}; diff --git a/src/components/tabs/tab.tsx b/src/components/tabs/tab.tsx index 698aefe2da8..8444ec82ecd 100644 --- a/src/components/tabs/tab.tsx +++ b/src/components/tabs/tab.tsx @@ -15,9 +15,11 @@ import React, { } from 'react'; import classNames from 'classnames'; import { CommonProps, ExclusiveUnion } from '../common'; -import { getSecureRelForTarget } from '../../services'; +import { getSecureRelForTarget, useEuiTheme } from '../../services'; import { validateHref } from '../../services/security/href_validator'; +import { euiTabStyles, euiTabsExpandedStyles } from './tab.styles'; + export interface EuiTabProps extends CommonProps { isSelected?: boolean; disabled?: boolean; @@ -58,18 +60,41 @@ export const EuiTab: FunctionComponent = ({ append, ...rest }) => { + const euiTheme = useEuiTheme(); const isHrefValid = !href || validateHref(href); const disabled = _disabled || !isHrefValid; + // Keep CSS classnames for reference const classes = classNames('euiTab', className, { 'euiTab-isSelected': isSelected, 'euiTab-isDisabled': disabled, }); + const tabStyles = euiTabStyles(euiTheme, disabled); + const computedStyles = [ + tabStyles.euiTab, + tabStyles.size_m, + //tabStyles[`size_${size}`], + isSelected && tabStyles.isSelected, + ]; + const tabContentStyles = () => { + if (isSelected) { + return tabStyles.euiTabContentSelected; + } else if (disabled) { + return tabStyles.euiTabContentDisabled; + } else return tabStyles.euiTabContentBase; + }; + const prependNode = prepend && ( - {prepend} + + {prepend} + + ); + const appendNode = append && ( + + {append} + ); - const appendNode = append && {append}; // elements don't respect the `disabled` attribute. So if we're disabled, we'll just pretend // this is a button and piggyback off its disabled styles. @@ -81,13 +106,16 @@ export const EuiTab: FunctionComponent = ({ role="tab" aria-selected={!!isSelected} className={classes} + css={computedStyles} href={href} target={target} rel={secureRel} {...(rest as AnchorHTMLAttributes)} > {prependNode} - {children} + + {children} + {appendNode} ); @@ -99,11 +127,14 @@ export const EuiTab: FunctionComponent = ({ aria-selected={!!isSelected} type="button" className={classes} + css={computedStyles} disabled={disabled} {...(rest as ButtonHTMLAttributes)} > {prependNode} - {children} + + {children} + {appendNode} ); diff --git a/src/components/tabs/tabs.tsx b/src/components/tabs/tabs.tsx index a580ae12b7a..cfe5ec629f6 100644 --- a/src/components/tabs/tabs.tsx +++ b/src/components/tabs/tabs.tsx @@ -14,10 +14,13 @@ import React, { } from 'react'; import classNames from 'classnames'; import { CommonProps, keysOf } from '../common'; +import { useEuiTheme } from '../../services'; + +import { euiTabsStyles } from './tab.styles'; const sizeToClassNameMap = { s: 'euiTabs--small', - m: null, + m: 'euiTabs--medium', l: 'euiTabs--large', xl: 'euiTabs--xlarge', }; @@ -62,6 +65,9 @@ export const EuiTabs = forwardRef>( }: PropsWithChildren, ref ) => { + const euiTheme = useEuiTheme(); + + // Keeps CSS classes for reference const classes = classNames( 'euiTabs', sizeToClassNameMap[size], @@ -72,10 +78,17 @@ export const EuiTabs = forwardRef>( className ); + const tabsStyles = euiTabsStyles(euiTheme); + const computedStyles = [ + tabsStyles.euiTabs, + bottomBorder && tabsStyles.bottomBorder, + ]; + return (
From 21eeb4d163597ee3bc1a87050211d25dcbeb3bdf Mon Sep 17 00:00:00 2001 From: Davey Holler Date: Thu, 13 Oct 2022 20:18:36 -0700 Subject: [PATCH 02/17] WIP Tabs emotion conversion --- src/components/index.scss | 1 - src/components/tabs/tab.styles.ts | 145 +++++++++++++-------- src/components/tabs/tab.tsx | 22 +--- src/components/tabs/tabs.tsx | 2 + src/themes/amsterdam/overrides/_index.scss | 1 - 5 files changed, 100 insertions(+), 71 deletions(-) diff --git a/src/components/index.scss b/src/components/index.scss index ced54713a92..12530e2af31 100644 --- a/src/components/index.scss +++ b/src/components/index.scss @@ -29,4 +29,3 @@ @import 'steps/index'; @import 'suggest/index'; @import 'table/index'; -@import 'tabs/index'; diff --git a/src/components/tabs/tab.styles.ts b/src/components/tabs/tab.styles.ts index 98292937ca0..97ca6e74edc 100644 --- a/src/components/tabs/tab.styles.ts +++ b/src/components/tabs/tab.styles.ts @@ -9,18 +9,11 @@ import { css } from '@emotion/react'; import { euiFontSize, logicalCSS } from '../../global_styling'; import { UseEuiTheme } from '../../services'; -import { EuiThemeComputed } from '../../services/theme/types'; -const selectedStyles = (euiTheme: EuiThemeComputed, isDisabled: boolean) => { - const selectedColor = isDisabled - ? euiTheme.colors.disabledText - : euiTheme.colors.primaryText; - return css` - box-shadow: inset 0 calc(${euiTheme.border.thick} - 1) 0 ${selectedColor}; - `; -}; +import { euiTitle } from '../title/title.styles'; -export const euiTabsStyles = ({ euiTheme }: UseEuiTheme) => { +export const euiTabsStyles = (euiThemeContext: UseEuiTheme) => { + const { euiTheme } = euiThemeContext; return { euiTabs: css` display: flex; @@ -34,15 +27,73 @@ export const euiTabsStyles = ({ euiTheme }: UseEuiTheme) => { box-shadow: inset 0 calc(${euiTheme.border.width.thin} * -1) 0 ${euiTheme.border.color}; `, - }; -}; -export const euiTabsExpandedStyles = () => { - return { - euiTabsExpanded: css` - flex-basis: 0%; - flex-grow: 1; - justify-content: center; + size_s: css` + .euiTab { + padding: ${euiTheme.size.s} ${euiTheme.size.xs}; + + & + .euiTab { + ${logicalCSS('margin-left', euiTheme.size.m)}; + } + } + + .euiTab__content { + ${euiTitle(euiThemeContext, 'xxxs')}; + } + `, + + // DEFAULT + size_m: css` + .euiTab { + padding: ${euiTheme.size.s} ${euiTheme.size.xs}; + + & + .euiTab { + ${logicalCSS('margin-left', euiTheme.size.base)}; + } + } + + .euiTab__content { + ${euiTitle(euiThemeContext, 'xxs')}; + } + `, + + size_l: css` + .euiTab { + padding: ${euiTheme.size.s} ${euiTheme.size.xs}; + + & + .euiTab { + ${logicalCSS('margin-left', euiTheme.size.l)}; + } + } + + .euiTab__content { + ${euiTitle(euiThemeContext, 'xs')}; + } + `, + + size_xl: css` + .euiTab { + padding: ${euiTheme.size.s} ${euiTheme.size.xs}; + + & + .euiTab { + ${logicalCSS('margin-left', euiTheme.size.xl)}; + } + } + + .euiTab__content { + font-size: calc(${euiTheme.size.base + euiTheme.size.xs}); + } + + line-height: calc(${euiFontSize(euiThemeContext, 'l').lineHeight} * 4.5); + ${logicalCSS('height', `calc(${euiTheme.size.base} * 4.5`)} + `, + + expanded: css` + .euiTab { + flex-basis: 0%; + flex-grow: 1; + justify-content: center; + } `, }; }; @@ -52,6 +103,10 @@ export const euiTabStyles = ( isDisabled: boolean ) => { const { euiTheme } = euiThemeContext; + const borderColor = isDisabled + ? euiTheme.colors.disabledText + : euiTheme.colors.primaryText; + return { euiTab: css` cursor: pointer; @@ -60,44 +115,34 @@ export const euiTabStyles = ( font-weight: ${euiTheme.font.weight.semiBold}; &:focus { - background-color: ${euiTheme.colors.lightestShade}; + background-color: ${euiTheme.colors.ghost}; outline-offset: -${euiTheme.focus.width}; } - `, - - euiTabContentBase: css` - color: ${euiTheme.colors.text}; - `, - - euiTabContentSelected: css` - color: ${euiTheme.colors.primaryText}; - `, - euiTabContentDisabled: css` - color: ${euiTheme.colors.disabledText}; - `, - - size_s: css` - padding: ${euiTheme.size.s}; - font-size: ${euiFontSize(euiThemeContext, 's').fontSize}; + .euiTab__content { + ${euiTitle(euiThemeContext, 'xxs')}; + color: ${euiTheme.colors.text}; + } `, - // DEFAULT - size_m: css` - padding: ${euiTheme.size.m} ${euiTheme.size.base}; - font-size: ${euiFontSize(euiThemeContext, 'm').fontSize}; + euiTabSelected: css` + box-shadow: inset 0 calc(${euiTheme.border.width.thick} * -1) 0 + ${borderColor}; + .euiTab__content { + ${euiTitle(euiThemeContext, 'xxs')}; + color: ${euiTheme.colors.primaryText}; + } `, - size_l: css` - padding: ${euiTheme.size.m} ${euiTheme.size.base}; - font-size: ${euiFontSize(euiThemeContext, 'm').fontSize}; - `, + euiTabDisabled: css` + &:hover { + cursor: not-allowed; + } - size_xl: css` - padding: ${euiTheme.size.s} ${euiTheme.size.l}; - font-size: ${euiFontSize(euiThemeContext, 'l').fontSize}; - line-height: calc(${euiFontSize(euiThemeContext, 'l').lineHeight} * 4.5); - ${logicalCSS('height', `calc(${euiTheme.size.base} * 4.5`)} + .euiTab__content { + ${euiTitle(euiThemeContext, 'xxs')}; + color: ${euiTheme.colors.disabledText}; + } `, prepend: css` @@ -109,9 +154,5 @@ export const euiTabStyles = ( ${logicalCSS('margin-left', euiTheme.size.s)}; color: ${euiTheme.colors[isDisabled ? 'disabledText' : 'text']}; `, - - isSelected: css` - ${selectedStyles(euiTheme, isDisabled)}; - `, }; }; diff --git a/src/components/tabs/tab.tsx b/src/components/tabs/tab.tsx index 8444ec82ecd..778e82bcc53 100644 --- a/src/components/tabs/tab.tsx +++ b/src/components/tabs/tab.tsx @@ -18,7 +18,7 @@ import { CommonProps, ExclusiveUnion } from '../common'; import { getSecureRelForTarget, useEuiTheme } from '../../services'; import { validateHref } from '../../services/security/href_validator'; -import { euiTabStyles, euiTabsExpandedStyles } from './tab.styles'; +import { euiTabStyles } from './tab.styles'; export interface EuiTabProps extends CommonProps { isSelected?: boolean; @@ -73,17 +73,9 @@ export const EuiTab: FunctionComponent = ({ const tabStyles = euiTabStyles(euiTheme, disabled); const computedStyles = [ tabStyles.euiTab, - tabStyles.size_m, - //tabStyles[`size_${size}`], - isSelected && tabStyles.isSelected, + isSelected && tabStyles.euiTabSelected, + disabled && tabStyles.euiTabDisabled, ]; - const tabContentStyles = () => { - if (isSelected) { - return tabStyles.euiTabContentSelected; - } else if (disabled) { - return tabStyles.euiTabContentDisabled; - } else return tabStyles.euiTabContentBase; - }; const prependNode = prepend && ( @@ -113,9 +105,7 @@ export const EuiTab: FunctionComponent = ({ {...(rest as AnchorHTMLAttributes)} > {prependNode} - - {children} - + {children} {appendNode} ); @@ -132,9 +122,7 @@ export const EuiTab: FunctionComponent = ({ {...(rest as ButtonHTMLAttributes)} > {prependNode} - - {children} - + {children} {appendNode} ); diff --git a/src/components/tabs/tabs.tsx b/src/components/tabs/tabs.tsx index cfe5ec629f6..8ffbd8f6355 100644 --- a/src/components/tabs/tabs.tsx +++ b/src/components/tabs/tabs.tsx @@ -81,7 +81,9 @@ export const EuiTabs = forwardRef>( const tabsStyles = euiTabsStyles(euiTheme); const computedStyles = [ tabsStyles.euiTabs, + tabsStyles[`size_${size}`], bottomBorder && tabsStyles.bottomBorder, + expand && tabsStyles.expanded, ]; return ( diff --git a/src/themes/amsterdam/overrides/_index.scss b/src/themes/amsterdam/overrides/_index.scss index 721733fee48..8d1e11becf6 100644 --- a/src/themes/amsterdam/overrides/_index.scss +++ b/src/themes/amsterdam/overrides/_index.scss @@ -24,4 +24,3 @@ @import 'range_tooltip'; @import 'side_nav'; @import 'steps'; -@import 'tabs'; From 75266dec367f714bac47713e83d30aa06f6271db Mon Sep 17 00:00:00 2001 From: Davey Holler Date: Fri, 14 Oct 2022 08:56:30 -0700 Subject: [PATCH 03/17] Rounding out the styles.ts file --- .../__snapshots__/page_header.test.tsx.snap | 6 +- .../page_header_content.test.tsx.snap | 18 +- .../tabs/__snapshots__/tab.test.tsx.snap | 16 +- .../tabs/__snapshots__/tabs.test.tsx.snap | 12 +- src/components/tabs/tab.styles.ts | 100 +- .../tabbed_content.test.tsx.snap | 1621 ++++++++++++++++- 6 files changed, 1611 insertions(+), 162 deletions(-) diff --git a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap index 814cb118f90..90e0d804709 100644 --- a/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap +++ b/src/components/page/page_header/__snapshots__/page_header.test.tsx.snap @@ -324,13 +324,13 @@ exports[`EuiPageHeader props page content props are passed down is rendered 1`] />
- - - + + + - - prepend - - - - Kibana - - - - append - - - + + + + + + + + + + + + + + + + + + + , + "ctr": 17, + "insertionPoint": undefined, + "isSpeedy": false, + "key": "css", + "nonce": undefined, + "prepend": undefined, + "tags": Array [ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ], + }, + } + } + isStringTag={true} + serialized={ + Object { + "map": undefined, + "name": "1luzeu0-euiTab-euiTabSelected", + "next": undefined, + "styles": "cursor:pointer;flex-direction:row;align-items:center;font-weight:600;&:focus{background-color:#FFF;outline-offset:-2px;}.euiTab__content{color:#343741;};label:euiTab;;;box-shadow:inset 0 calc(2px * -1) 0 #006bb8;.euiTab__content{color:#006bb8;};label:euiTabSelected;;;;", + "toString": [Function], + } + } + /> + + + +
@@ -1775,7 +981,7 @@ exports[`EuiTabbedContent is rendered with required props and tabs 1`] = ` ); diff --git a/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.tsx.snap b/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.tsx.snap index 94535f7e547..1ef55c14bbd 100644 --- a/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.tsx.snap +++ b/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.tsx.snap @@ -3,19 +3,19 @@ exports[`EuiTabbedContent behavior when selected tab state isn't controlled by the owner, select the first tab by default 1`] = `
@@ -655,9 +1055,10 @@ exports[`EuiTabbedContent behavior when uncontrolled, the selected tab should up data-test-subj="kibanaTab" id="kibana" isSelected={true} - key="kibana" + key=".$kibana" onClick={[Function]} prepend="prepend" + size="m" >