diff --git a/src-docs/src/views/description_list/description_list.js b/src-docs/src/views/description_list/description_list.js index 57ce3b180f8..de880e98aa4 100644 --- a/src-docs/src/views/description_list/description_list.js +++ b/src-docs/src/views/description_list/description_list.js @@ -1,12 +1,6 @@ import React from 'react'; -import { - EuiDescriptionList, - EuiFlexItem, - EuiFlexGroup, - EuiDescriptionListTitle, - EuiDescriptionListDescription, -} from '../../../../src/components'; +import { EuiDescriptionList } from '../../../../src/components'; const favoriteVideoGames = [ { @@ -16,29 +10,11 @@ const favoriteVideoGames = [ { title: 'TIE Fighter', description: - 'The sequel to XWING, join the dark side and fly for the Emporer.', + 'The sequel to XWING, join the dark side and fly for the Emperor.', }, { title: 'Quake 2', description: 'The game that made me drop out of college.', }, ]; -export default () => ( - - - - - - - Dota 2 - - A videogame that I have spent way too much time on over the years. - - Kings Quest VI - - The game that forced me to learn DOS. - - - - -); +export default () => ; diff --git a/src-docs/src/views/description_list/description_list_column.js b/src-docs/src/views/description_list/description_list_column.js index 78413323fcf..a6b7577c696 100644 --- a/src-docs/src/views/description_list/description_list_column.js +++ b/src-docs/src/views/description_list/description_list_column.js @@ -1,10 +1,6 @@ -import React, { Fragment } from 'react'; +import React from 'react'; -import { - EuiDescriptionList, - EuiSpacer, - EuiTitle, -} from '../../../../src/components'; +import { EuiDescriptionList } from '../../../../src/components'; const favoriteVideoGames = [ { @@ -22,27 +18,9 @@ const favoriteVideoGames = [ }, ]; export default () => ( - - - - - - -

- The following list will become the typical row format on small screens -

-
- - - - -
+ ); diff --git a/src-docs/src/views/description_list/description_list_column_responsive.js b/src-docs/src/views/description_list/description_list_column_responsive.js new file mode 100644 index 00000000000..9c597603a2d --- /dev/null +++ b/src-docs/src/views/description_list/description_list_column_responsive.js @@ -0,0 +1,26 @@ +import React from 'react'; + +import { EuiDescriptionList } from '../../../../src/components'; + +const favoriteVideoGames = [ + { + title: 'The Elder Scrolls: Morrowind', + description: 'The opening music alone evokes such strong memories.', + }, + { + title: 'TIE Fighter', + description: + 'The sequel to XWING, join the dark side and fly for the Emporer.', + }, + { + title: 'Quake 2', + description: 'The game that made me drop out of college.', + }, +]; +export default () => ( + +); diff --git a/src-docs/src/views/description_list/description_list_example.js b/src-docs/src/views/description_list/description_list_example.js index 440bdaf19a8..85057fdf721 100644 --- a/src-docs/src/views/description_list/description_list_example.js +++ b/src-docs/src/views/description_list/description_list_example.js @@ -9,6 +9,8 @@ import { EuiDescriptionListDescription, } from '../../../../src/components'; +import { descriptionListConfig } from './playground'; + import DescriptionList from './description_list'; const descriptionListSource = require('!!raw-loader!./description_list'); const descriptionListSnippet = [ @@ -20,26 +22,42 @@ const descriptionListSnippet = [ }, ]} />`, +]; + +import DescriptionListSeparate from './description_list_separate'; +const descriptionListSeparateSource = require('!!raw-loader!./description_list_separate'); +const descriptionListSeparateSnippet = [ ` - Dota 2 + + The Elder Scrolls: Morrowind + - A videogame that I have spent way too much time on over the years. + The opening music alone evokes such strong memories. + TIE Fighter + + The sequel to XWING, join the dark side and fly for the Emperor. + + Quake 2 + + The game that made me drop out of college. + `, ]; import DescriptionListColumn from './description_list_column'; const descriptionListColumnSource = require('!!raw-loader!./description_list_column'); -const descriptionListColumnSnippet = [ - ``, - ``; + +import DescriptionListResponsiveColumn from './description_list_column_responsive'; +const descriptionListResponsiveColumnSource = require('!!raw-loader!./description_list_column_responsive'); +const descriptionListResponsiveColumnSnippet = ``, -]; +/>`; import DescriptionListStyling from './description_list_styling'; const descriptionListStylingSource = require('!!raw-loader!./description_list_styling'); @@ -93,10 +111,7 @@ export const DescriptionListExample = {

EuiDescriptionList is a component for listing pairs of information together. You can use the component on its own, passing - in an object for the list, or use the{' '} - EuiDescriptionListTitle and{' '} - EuiDescriptionListDescription components separately - to build a list manually. + in an object for the list.

), props: { @@ -106,6 +121,30 @@ export const DescriptionListExample = { }, snippet: descriptionListSnippet, demo: , + playground: descriptionListConfig, + }, + { + source: [ + { + type: GuideSectionTypes.JS, + code: descriptionListSeparateSource, + }, + ], + text: ( +

+ You can also use the EuiDescriptionListTitle and{' '} + EuiDescriptionListDescription components separately + to build a list manually. +

+ ), + props: { + EuiDescriptionList, + EuiDescriptionListTitle, + EuiDescriptionListDescription, + }, + snippet: descriptionListSeparateSnippet, + demo: , + playground: descriptionListConfig, }, { title: 'Reverse style', @@ -148,14 +187,29 @@ export const DescriptionListExample = { column description lists can be presented in an inline, column format.

+ + ), + snippet: descriptionListColumnSnippet, + demo: , + }, + { + source: [ + { + type: GuideSectionTypes.JS, + code: descriptionListResponsiveColumnSource, + }, + ], + text: ( +

To return to the typical row format on smaller screens set{' '} - type to responsiveColumn. + type to responsiveColumn. The + following list will only show the column format on larger screens.

), - snippet: descriptionListColumnSnippet, - demo: , + snippet: descriptionListResponsiveColumnSnippet, + demo: , }, { title: 'Inline', diff --git a/src-docs/src/views/description_list/description_list_separate.js b/src-docs/src/views/description_list/description_list_separate.js new file mode 100644 index 00000000000..8652e97ce66 --- /dev/null +++ b/src-docs/src/views/description_list/description_list_separate.js @@ -0,0 +1,26 @@ +import React from 'react'; + +import { + EuiDescriptionList, + EuiDescriptionListTitle, + EuiDescriptionListDescription, +} from '../../../../src/components'; + +export default () => ( + + + The Elder Scrolls: Morrowind + + + The opening music alone evokes such strong memories. + + TIE Fighter + + The sequel to XWING, join the dark side and fly for the Emperor. + + Quake 2 + + The game that made me drop out of college. + + +); diff --git a/src-docs/src/views/description_list/playground.js b/src-docs/src/views/description_list/playground.js new file mode 100644 index 00000000000..66dbc9c43a1 --- /dev/null +++ b/src-docs/src/views/description_list/playground.js @@ -0,0 +1,46 @@ +import { EuiDescriptionList } from '../../../../src/components'; +import { + propUtilityForPlayground, + generateCustomProps, +} from '../../services/playground'; + +export const descriptionListConfig = () => { + const docgenInfo = Array.isArray(EuiDescriptionList.__docgenInfo) + ? EuiDescriptionList.__docgenInfo[0] + : EuiDescriptionList.__docgenInfo; + const propsToUse = propUtilityForPlayground(docgenInfo.props); + + const listItems = `[ + { + title: 'The Elder Scrolls: Morrowind', + description: 'The opening music alone evokes such strong memories.', + }, + { + title: 'TIE Fighter', + description: + 'The sequel to XWING, join the dark side and fly for the Emporer.', + }, + ]`; + propsToUse.listItems = { + ...propsToUse.listItems, + value: listItems, + }; + + return { + config: { + componentName: 'EuiSuggest', + props: propsToUse, + scope: { + EuiSuggest: EuiDescriptionList, + }, + imports: { + '@elastic/eui': { + named: ['EuiDescriptionList'], + }, + }, + customProps: { + ...generateCustomProps(['listItems']), + }, + }, + }; +}; diff --git a/src/components/description_list/__snapshots__/description_list.test.tsx.snap b/src/components/description_list/__snapshots__/description_list.test.tsx.snap index 828e8f61e91..11c29eb1855 100644 --- a/src/components/description_list/__snapshots__/description_list.test.tsx.snap +++ b/src/components/description_list/__snapshots__/description_list.test.tsx.snap @@ -2,39 +2,40 @@ exports[` 1`] = `
Title 1
Description 1
Title 2
Description 2
Title 3
Description 3
@@ -44,8 +45,9 @@ exports[` 1`] = ` exports[`EuiDescriptionList is rendered 1`] = `
Content
@@ -53,40 +55,44 @@ exports[`EuiDescriptionList is rendered 1`] = ` exports[`EuiDescriptionList props align center is rendered 1`] = `
`; exports[`EuiDescriptionList props align left is rendered 1`] = `
`; exports[`EuiDescriptionList props compressed is rendered 1`] = `
`; exports[`EuiDescriptionList props listItems descriptionProps is rendered 1`] = `
Title 1
Description 1
Title 2 @@ -94,7 +100,7 @@ exports[`EuiDescriptionList props listItems descriptionProps is rendered 1`] = `
@@ -102,13 +108,13 @@ exports[`EuiDescriptionList props listItems descriptionProps is rendered 1`] = `
Title 3
Description 3 @@ -118,23 +124,24 @@ exports[`EuiDescriptionList props listItems descriptionProps is rendered 1`] = ` exports[`EuiDescriptionList props listItems titleProps is rendered 1`] = `
Title 1
Description 1
@@ -142,7 +149,7 @@ exports[`EuiDescriptionList props listItems titleProps is rendered 1`] = `
Description 2 @@ -150,13 +157,13 @@ exports[`EuiDescriptionList props listItems titleProps is rendered 1`] = `
Title 3
Description 3
@@ -165,24 +172,28 @@ exports[`EuiDescriptionList props listItems titleProps is rendered 1`] = ` exports[`EuiDescriptionList props type column is rendered 1`] = `
`; exports[`EuiDescriptionList props type inline is rendered 1`] = `
`; exports[`EuiDescriptionList props type responsiveColumn is rendered 1`] = `
`; exports[`EuiDescriptionList props type row is rendered 1`] = `
`; diff --git a/src/components/description_list/__snapshots__/description_list_description.test.tsx.snap b/src/components/description_list/__snapshots__/description_list_description.test.tsx.snap index 73afd8b550d..cd61805364b 100644 --- a/src/components/description_list/__snapshots__/description_list_description.test.tsx.snap +++ b/src/components/description_list/__snapshots__/description_list_description.test.tsx.snap @@ -1,9 +1,51 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`EuiDescriptionListDescription EuiDescriptionListDescription prop variations align center alignment is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListDescription EuiDescriptionListDescription prop variations compressed is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListDescription EuiDescriptionListDescription prop variations text styles reversed text is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListDescription EuiDescriptionListDescription prop variations type column is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListDescription EuiDescriptionListDescription prop variations type inline is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListDescription EuiDescriptionListDescription prop variations type responsiveColumn is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListDescription EuiDescriptionListDescription prop variations type row is rendered 1`] = ` +
+`; + exports[`EuiDescriptionListDescription is rendered 1`] = `
Content diff --git a/src/components/description_list/__snapshots__/description_list_title.test.tsx.snap b/src/components/description_list/__snapshots__/description_list_title.test.tsx.snap index 0b93e495fdf..0e27083ec4b 100644 --- a/src/components/description_list/__snapshots__/description_list_title.test.tsx.snap +++ b/src/components/description_list/__snapshots__/description_list_title.test.tsx.snap @@ -1,9 +1,51 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`EuiDescriptionListTitle EuiDescriptionListTitle prop variations align center alignment is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListTitle EuiDescriptionListTitle prop variations compressed is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListTitle EuiDescriptionListTitle prop variations text styles reversed text is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListTitle EuiDescriptionListTitle prop variations type column is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListTitle EuiDescriptionListTitle prop variations type inline is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListTitle EuiDescriptionListTitle prop variations type responsiveColumn is rendered 1`] = ` +
+`; + +exports[`EuiDescriptionListTitle EuiDescriptionListTitle prop variations type row is rendered 1`] = ` +
+`; + exports[`EuiDescriptionListTitle is rendered 1`] = `
Content diff --git a/src/components/description_list/_description_list.scss b/src/components/description_list/_description_list.scss deleted file mode 100644 index d4d6a38f439..00000000000 --- a/src/components/description_list/_description_list.scss +++ /dev/null @@ -1,211 +0,0 @@ -.euiDescriptionList { - // sass-lint:disable-block nesting-depth - - &.euiDescriptionList--row { - - .euiDescriptionList__title { - @include euiTitle('xs'); - line-height: $euiLineHeight; - margin-top: $euiSize; - - // Make sure the first
doesn't get a margin. - &:first-of-type { - margin-top: 0; - } - } - - .euiDescriptionList__description { - @include euiFontSizeS; - } - - // Lists can be aligned. - &.euiDescriptionList--center { - text-align: center; - } - - // Reversed makes the description larger than the title - &.euiDescriptionList--reverse { - .euiDescriptionList__title { - @include euiText; - @include euiFontSizeS; - } - - .euiDescriptionList__description { - @include euiTitle('xs'); - } - } - - // Compressed gets smaller fonts. - &.euiDescriptionList--compressed { - - .euiDescriptionList__title { - @include euiTitle('xxs'); - line-height: $euiLineHeight; - } - - .euiDescriptionList__description { - @include euiFontSizeS; - } - - &.euiDescriptionList--reverse { - .euiDescriptionList__title { - @include euiText; - @include euiFontSizeS; - } - - .euiDescriptionList__description { - @include euiTitle('xxs'); - line-height: $euiLineHeight; - } - } - } - } - - - &.euiDescriptionList--column, - &.euiDescriptionList--responsiveColumn { - display: flex; - align-items: stretch; - flex-wrap: wrap; - - > * { - margin-top: $euiSize; - } - - // First two items don't have margin - > *:first-child, - > :nth-child(2) { - margin-top: 0; - } - - .euiDescriptionList__title { - @include euiTitle('xs'); - line-height: $euiLineHeight; - width: 50%; // Flex-basis doesn't work in IE with padding - padding-right: $euiSizeS; - } - - .euiDescriptionList__description { - @include euiFontSize; - width: 50%; // Flex-basis doesn't work in IE with padding - padding-left: $euiSizeS; - } - - // Align the title to smash against the description. - &.euiDescriptionList--center { - .euiDescriptionList__title { - text-align: right; - } - } - - &.euiDescriptionList--reverse { - .euiDescriptionList__title { - @include euiText; - @include euiFontSize; - } - - .euiDescriptionList__description { - @include euiTitle('xs'); - line-height: $euiLineHeight; - } - } - - &.euiDescriptionList--compressed { - .euiDescriptionList__title { - @include euiTitle('xxs'); - line-height: $euiLineHeight; - } - - .euiDescriptionList__description { - @include euiFontSizeS; - } - - &.euiDescriptionList--reverse { - .euiDescriptionList__title { - @include euiText; - @include euiFontSizeS; - } - - .euiDescriptionList__description { - @include euiTitle('xxs'); - line-height: $euiLineHeight; - } - } - } - } - - &.euiDescriptionList--responsiveColumn { - @include euiBreakpoint('xs', 's') { - display: block; - - .euiDescriptionList__title, - .euiDescriptionList__description { - width: 100%; - padding: 0; - } - - .euiDescriptionList__description { - @include euiFontSizeS; - margin-top: 0; - } - - &.euiDescriptionList--center { - .euiDescriptionList__title, - .euiDescriptionList__description { - text-align: center; - } - } - - &.euiDescriptionList--reverse { - .euiDescriptionList__title { - @include euiFontSizeS; - } - - .euiDescriptionList__description { - @include euiTitle('xs'); - } - } - } - } - - &.euiDescriptionList--inline { - - .euiDescriptionList__title { - @include euiFontSizeS; - display: inline; - border-radius: $euiBorderRadiusSmall; - font-weight: $euiFontWeightMedium; - background-color: tintOrShade($euiColorLightShade, 50%, 0%); - padding: 1px $euiSizeXS; - margin: 0 $euiSizeXS; - - // Make sure the first
doesn't get a margin. - &:first-of-type { - margin-left: 0; - } - } - - .euiDescriptionList__description { - @include euiFontSizeS; - display: inline; - } - - // Compressed when inline is even smaller. - &.euiDescriptionList--compressed { - - .euiDescriptionList__title { - @include euiFontSizeXS; - padding: 0 $euiSizeXS; - } - - .euiDescriptionList__description { - @include euiFontSizeXS; - } - } - - &.euiDescriptionList--center { - text-align: center; - } - } - -} \ No newline at end of file diff --git a/src/components/description_list/_index.scss b/src/components/description_list/_index.scss deleted file mode 100644 index d2e24225436..00000000000 --- a/src/components/description_list/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'description_list'; diff --git a/src/components/description_list/description_list.styles.ts b/src/components/description_list/description_list.styles.ts new file mode 100644 index 00000000000..d8c99a79efe --- /dev/null +++ b/src/components/description_list/description_list.styles.ts @@ -0,0 +1,45 @@ +/* + * 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 { logicalTextAlignCSS, euiBreakpoint } from '../../global_styling'; +import { UseEuiTheme } from '../../services'; + +export const euiDescriptionListStyles = (euiThemeContext: UseEuiTheme) => { + // Flex display for column and responsive column + const columnDisplay = ` + display: flex; + align-items: baseline; + flex-wrap: wrap; + `; + + return { + euiDescriptionList: css``, + + // Types + row: css``, + inline: css``, + column: css` + ${columnDisplay} + `, + // Responsive columns behave as a row on breakpoints xs-s + responsiveColumn: css` + ${euiBreakpoint(euiThemeContext, ['m', 'xl'])} { + ${columnDisplay} + } + `, + + // Alignment + center: css` + ${logicalTextAlignCSS('center')} + `, + left: css` + ${logicalTextAlignCSS('left')} + `, + }; +}; diff --git a/src/components/description_list/description_list.test.tsx b/src/components/description_list/description_list.test.tsx index e0365eb3343..795f7fc0ecb 100644 --- a/src/components/description_list/description_list.test.tsx +++ b/src/components/description_list/description_list.test.tsx @@ -10,9 +10,13 @@ import React from 'react'; import { render } from 'enzyme'; import { requiredProps } from '../../test/required_props'; -import { EuiDescriptionList, TYPES, ALIGNMENTS } from './description_list'; +import { EuiDescriptionList } from './description_list'; +import { TYPES, ALIGNMENTS } from './description_list_types'; +import { shouldRenderCustomStyles } from '../../test/internal'; describe('EuiDescriptionList', () => { + shouldRenderCustomStyles(); + test('is rendered', () => { const component = render( Content diff --git a/src/components/description_list/description_list.tsx b/src/components/description_list/description_list.tsx index 30c4599f8ea..d338eca33da 100644 --- a/src/components/description_list/description_list.tsx +++ b/src/components/description_list/description_list.tsx @@ -6,72 +6,20 @@ * Side Public License, v 1. */ -import React, { HTMLAttributes, ReactNode, FunctionComponent } from 'react'; +import React, { HTMLAttributes, FunctionComponent } from 'react'; import classNames from 'classnames'; import { EuiDescriptionListTitle } from './description_list_title'; import { EuiDescriptionListDescription } from './description_list_description'; -import { CommonProps, keysOf } from '../common'; +import { CommonProps } from '../common'; -export type EuiDescriptionListType = keyof typeof typesToClassNameMap; -export type EuiDescriptionListAlignment = keyof typeof alignmentsToClassNameMap; -export type EuiDescriptionListTextStyle = keyof typeof textStylesToClassNameMap; +import { useEuiTheme } from '../../services'; +import { euiDescriptionListStyles } from './description_list.styles'; -export interface EuiDescriptionListProps { - listItems?: Array<{ - title: NonNullable; - description: NonNullable; - }>; - /** - * Text alignment - */ - align?: EuiDescriptionListAlignment; - /** - * Smaller text and condensed spacing - */ - compressed?: boolean; - /** - * How should the content be styled, by default - * this will emphasize the title - */ - textStyle?: EuiDescriptionListTextStyle; - /** - * How each item should be laid out - */ - type?: EuiDescriptionListType; - /** - * Props object to be passed to `EuiDescriptionListTitle` - */ - titleProps?: HTMLAttributes & CommonProps; - /** - * Props object to be passed to `EuiDescriptionListDescription` - */ - descriptionProps?: HTMLAttributes & CommonProps; -} +import { EuiDescriptionListProps } from './description_list_types'; -const typesToClassNameMap = { - row: 'euiDescriptionList--row', - inline: 'euiDescriptionList--inline', - column: 'euiDescriptionList--column', - responsiveColumn: 'euiDescriptionList--responsiveColumn', -}; - -export const TYPES = keysOf(typesToClassNameMap); - -const alignmentsToClassNameMap = { - center: 'euiDescriptionList--center', - left: '', -}; - -export const ALIGNMENTS = keysOf(alignmentsToClassNameMap); - -const textStylesToClassNameMap = { - normal: '', - reverse: 'euiDescriptionList--reverse', -}; - -export const TEXT_STYLES = keysOf(textStylesToClassNameMap); +import { EuiDescriptionListContext } from './description_list_context'; export const EuiDescriptionList: FunctionComponent< CommonProps & HTMLAttributes & EuiDescriptionListProps @@ -87,18 +35,15 @@ export const EuiDescriptionList: FunctionComponent< type = 'row', ...rest }) => { - const classes = classNames( - 'euiDescriptionList', - type ? typesToClassNameMap[type] : undefined, - align ? alignmentsToClassNameMap[align] : undefined, - textStyle ? textStylesToClassNameMap[textStyle] : undefined, - { - 'euiDescriptionList--compressed': compressed, - }, - className - ); + const euiTheme = useEuiTheme(); + const styles = euiDescriptionListStyles(euiTheme); + + const cssStyles = [styles.euiDescriptionList, styles[type], styles[align]]; + + const classes = classNames('euiDescriptionList', className); let childrenOrListItems = null; + if (listItems) { childrenOrListItems = listItems.map((item, index) => { return [ @@ -119,8 +64,12 @@ export const EuiDescriptionList: FunctionComponent< } return ( -
- {childrenOrListItems} -
+ +
+ {childrenOrListItems} +
+
); }; diff --git a/src/components/description_list/description_list_context.tsx b/src/components/description_list/description_list_context.tsx new file mode 100644 index 00000000000..de95acacfce --- /dev/null +++ b/src/components/description_list/description_list_context.tsx @@ -0,0 +1,24 @@ +/* + * 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 { createContext } from 'react'; +import { EuiDescriptionListProps } from './description_list_types'; + +type EuiDescriptionListContextValues = Required< + Pick +> & { compressed?: EuiDescriptionListProps['compressed'] }; + +export const contextDefaults: EuiDescriptionListContextValues = { + type: 'row', + textStyle: 'normal', + align: 'left', +}; + +export const EuiDescriptionListContext = createContext< + EuiDescriptionListContextValues +>(contextDefaults); diff --git a/src/components/description_list/description_list_description.styles.ts b/src/components/description_list/description_list_description.styles.ts new file mode 100644 index 00000000000..46d2aa013c0 --- /dev/null +++ b/src/components/description_list/description_list_description.styles.ts @@ -0,0 +1,81 @@ +/* + * 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, + euiBreakpoint, + logicalTextAlignCSS, + logicalCSS, +} from '../../global_styling'; +import { UseEuiTheme } from '../../services'; +import { euiTitle } from '../title/title.styles'; + +export const euiDescriptionListDescriptionStyles = ( + euiThemeContext: UseEuiTheme +) => { + const { euiTheme } = euiThemeContext; + + const columnDisplay = ` + ${logicalCSS('width', '50%')} // Flex-basis doesn't work in IE with padding + ${logicalCSS('padding-left', euiTheme.size.s)} + &:not(:first-of-type) { + ${logicalCSS('margin-top', euiTheme.size.base)} + } + `; + + return { + euiDescriptionList__description: css``, + + // Types + row: css``, + column: css` + ${columnDisplay} + `, + responsiveColumn: css` + ${euiBreakpoint(euiThemeContext, ['xs', 's'])} { + ${logicalCSS('width', '100%')} + padding: 0; + } + ${euiBreakpoint(euiThemeContext, ['m', 'xl'])} { + ${columnDisplay} + } + `, + inline: css` + display: inline; + `, + + // This nested block handles just the font styling based on compressed and reverse + fontStyles: { + normal: css` + ${euiFontSize(euiThemeContext, 's')}; + `, + reverse: css` + ${euiTitle(euiThemeContext, 'xs')} + `, + compressed: css` + ${euiTitle(euiThemeContext, 'xxs')} + `, + }, + + // Nested inline styles for type and font + inlineStyles: { + compressed: css` + ${euiFontSize(euiThemeContext, 'xs')}; + `, + normal: css` + ${euiFontSize(euiThemeContext, 's')}; + `, + }, + + // Column types should align description text to the left when EuiDecriptionList is centered + left: css` + ${logicalTextAlignCSS('left')}; + `, + }; +}; diff --git a/src/components/description_list/description_list_description.test.tsx b/src/components/description_list/description_list_description.test.tsx index 33e25a13551..4d1b05f432c 100644 --- a/src/components/description_list/description_list_description.test.tsx +++ b/src/components/description_list/description_list_description.test.tsx @@ -11,8 +11,16 @@ import { render } from 'enzyme'; import { requiredProps } from '../../test/required_props'; import { EuiDescriptionListDescription } from './description_list_description'; +import { TYPES } from './description_list_types'; +import { shouldRenderCustomStyles } from '../../test/internal'; +import { + EuiDescriptionListContext, + contextDefaults, +} from './description_list_context'; describe('EuiDescriptionListDescription', () => { + shouldRenderCustomStyles(); + test('is rendered', () => { const component = render( @@ -22,4 +30,64 @@ describe('EuiDescriptionListDescription', () => { expect(component).toMatchSnapshot(); }); + + describe('EuiDescriptionListDescription prop variations', () => { + describe('type', () => { + TYPES.forEach((type) => { + test(`${type} is rendered`, () => { + const component = render( + + + + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); + + describe('align', () => { + test('center alignment is rendered', () => { + const component = render( + + + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('text styles', () => { + test('reversed text is rendered', () => { + const component = render( + + + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('compressed', () => { + test('is rendered', () => { + const component = render( + + + + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); }); diff --git a/src/components/description_list/description_list_description.tsx b/src/components/description_list/description_list_description.tsx index 020f83518fc..876ea185229 100644 --- a/src/components/description_list/description_list_description.tsx +++ b/src/components/description_list/description_list_description.tsx @@ -6,17 +6,58 @@ * Side Public License, v 1. */ -import React, { HTMLAttributes, FunctionComponent } from 'react'; +import React, { HTMLAttributes, FunctionComponent, useContext } from 'react'; import classNames from 'classnames'; import { CommonProps } from '../common'; +import { useEuiTheme } from '../../services'; +import { euiDescriptionListDescriptionStyles } from './description_list_description.styles'; +import { EuiDescriptionListContext } from './description_list_context'; -export const EuiDescriptionListDescription: FunctionComponent< - CommonProps & HTMLAttributes -> = ({ children, className, ...rest }) => { - const classes = classNames('euiDescriptionList__description', className); +interface EuiDescriptionListDescriptionProps + extends CommonProps, + HTMLAttributes {} + +export const EuiDescriptionListDescription: FunctionComponent = ({ + children, + className, + ...rest +}) => { + const { type, textStyle, compressed, align } = useContext( + EuiDescriptionListContext + ); + + const theme = useEuiTheme(); + const styles = euiDescriptionListDescriptionStyles(theme); + + let conditionalStyles = + compressed && textStyle === 'reverse' + ? [styles.fontStyles.compressed] + : [styles.fontStyles[textStyle]]; + switch (type) { + case 'inline': + conditionalStyles = compressed + ? [styles.inlineStyles.compressed] + : [styles.inlineStyles.normal]; + break; + + case 'responsiveColumn': + case 'column': + if (align === 'center') { + conditionalStyles.push(styles.left); + } + break; + } + + const cssStyles = [ + styles.euiDescriptionList__description, + styles[type], + ...conditionalStyles, + ]; + + const classes = classNames('euiDescriptionList__description', className); return ( -
+
{children}
); diff --git a/src/components/description_list/description_list_title.styles.ts b/src/components/description_list/description_list_title.styles.ts new file mode 100644 index 00000000000..b6c186b8e6f --- /dev/null +++ b/src/components/description_list/description_list_title.styles.ts @@ -0,0 +1,98 @@ +/* + * 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, + euiTextBreakWord, + logicalTextAlignCSS, + euiBreakpoint, + logicalCSS, +} from '../../global_styling'; +import { tint, UseEuiTheme } from '../../services'; +import { euiTitle } from '../title/title.styles'; + +export const euiDescriptionListTitleStyles = (euiThemeContext: UseEuiTheme) => { + const { euiTheme, colorMode } = euiThemeContext; + + const columnDisplay = ` + ${logicalCSS('width', '50%')} // Flex-basis doesn't work in IE with padding + ${logicalCSS('padding-right', euiTheme.size.s)} + `; + return { + euiDescriptionList__title: css` + ${euiTextBreakWord()} + // Add margin only to the non-first
. + &:not(:first-of-type) { + ${logicalCSS('margin-top', euiTheme.size.base)} + } + `, + + // Types + row: css``, + column: css` + ${columnDisplay} + `, + responsiveColumn: css` + ${euiBreakpoint(euiThemeContext, ['xs', 's'])} { + ${logicalCSS('width', '100%')} + padding: 0; + } + ${euiBreakpoint(euiThemeContext, ['m', 'xl'])} { + ${columnDisplay} + } + `, + inline: css` + display: inline; + border-radius: ${euiTheme.border.radius.small}; + font-weight: ${euiTheme.font.weight.medium}; + background-color: ${colorMode === 'DARK' + ? tint(euiTheme.colors.lightestShade, 0.5) + : euiTheme.colors.lightestShade}; + ${logicalCSS('margin-vertical', '0')} + ${logicalCSS('margin-horizontal', euiTheme.size.xs)} + + // Make sure the first
doesn't get a margin. + &:first-of-type { + ${logicalCSS('margin-left', '0')} + } + `, + + // This nested block handles just the font styling based on compressed and reverse + fontStyles: { + normal: css` + ${euiTitle(euiThemeContext, 'xs')}; + `, + reverse: css` + ${euiFontSize(euiThemeContext, 's')}; + `, + compressed: css` + ${euiTitle(euiThemeContext, 'xxs')} + `, + }, + + // Inline types + inlineStyles: { + normal: css` + ${euiFontSize(euiThemeContext, 's')}; + ${logicalCSS('padding-vertical', '1px')} + ${logicalCSS('padding-horizontal', euiTheme.size.xs)} + `, + compressed: css` + ${euiFontSize(euiThemeContext, 'xs')}; + ${logicalCSS('padding-vertical', '0')} + ${logicalCSS('padding-horizontal', euiTheme.size.xs)} + `, + }, + + // Alignment + right: css` + ${logicalTextAlignCSS('right')}; + `, + }; +}; diff --git a/src/components/description_list/description_list_title.test.tsx b/src/components/description_list/description_list_title.test.tsx index 9cf380e5020..9fc2537d8ae 100644 --- a/src/components/description_list/description_list_title.test.tsx +++ b/src/components/description_list/description_list_title.test.tsx @@ -11,8 +11,16 @@ import { render } from 'enzyme'; import { requiredProps } from '../../test/required_props'; import { EuiDescriptionListTitle } from './description_list_title'; +import { shouldRenderCustomStyles } from '../../test/internal'; +import { TYPES } from './description_list_types'; +import { + EuiDescriptionListContext, + contextDefaults, +} from './description_list_context'; describe('EuiDescriptionListTitle', () => { + shouldRenderCustomStyles(); + test('is rendered', () => { const component = render( @@ -22,4 +30,64 @@ describe('EuiDescriptionListTitle', () => { expect(component).toMatchSnapshot(); }); + + describe('EuiDescriptionListTitle prop variations', () => { + describe('type', () => { + TYPES.forEach((type) => { + test(`${type} is rendered`, () => { + const component = render( + + + + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); + + describe('align', () => { + test('center alignment is rendered', () => { + const component = render( + + + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('text styles', () => { + test('reversed text is rendered', () => { + const component = render( + + + + ); + + expect(component).toMatchSnapshot(); + }); + }); + + describe('compressed', () => { + test('is rendered', () => { + const component = render( + + + + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); }); diff --git a/src/components/description_list/description_list_title.tsx b/src/components/description_list/description_list_title.tsx index 23b02470e7a..9f8229ce497 100644 --- a/src/components/description_list/description_list_title.tsx +++ b/src/components/description_list/description_list_title.tsx @@ -6,17 +6,59 @@ * Side Public License, v 1. */ -import React, { HTMLAttributes, FunctionComponent } from 'react'; +import React, { HTMLAttributes, FunctionComponent, useContext } from 'react'; import classNames from 'classnames'; import { CommonProps } from '../common'; +import { useEuiTheme } from '../../services'; +import { euiDescriptionListTitleStyles } from './description_list_title.styles'; +import { EuiDescriptionListContext } from './description_list_context'; + +interface EuiDescriptionListTitleProps + extends CommonProps, + HTMLAttributes {} + +export const EuiDescriptionListTitle: FunctionComponent = ({ + children, + className, + ...rest +}) => { + const { type, textStyle, compressed, align } = useContext( + EuiDescriptionListContext + ); + + const theme = useEuiTheme(); + const styles = euiDescriptionListTitleStyles(theme); + + let conditionalStyles = + compressed && textStyle === 'reverse' + ? [styles.fontStyles.compressed] + : [styles.fontStyles[textStyle]]; + + switch (type) { + case 'inline': + conditionalStyles = compressed + ? [styles.inlineStyles.compressed] + : [styles.inlineStyles.normal]; + break; + + case 'responsiveColumn': + case 'column': + if (align === 'center') { + conditionalStyles.push(styles.right); + } + break; + } + + const cssStyles = [ + styles.euiDescriptionList__title, + styles[type], + ...conditionalStyles, + ]; -export const EuiDescriptionListTitle: FunctionComponent< - CommonProps & HTMLAttributes -> = ({ children, className, ...rest }) => { const classes = classNames('euiDescriptionList__title', className); return ( -
+
{children}
); diff --git a/src/components/description_list/description_list_types.ts b/src/components/description_list/description_list_types.ts new file mode 100644 index 00000000000..c4f748066bd --- /dev/null +++ b/src/components/description_list/description_list_types.ts @@ -0,0 +1,51 @@ +/* + * 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 { HTMLAttributes, ReactNode } from 'react'; +import { CommonProps } from '../common'; + +export interface EuiDescriptionListProps { + listItems?: Array<{ + title: NonNullable; + description: NonNullable; + }>; + /** + * Text alignment + */ + align?: EuiDescriptionListAlignment; + /** + * Smaller text and condensed spacing + */ + compressed?: boolean; + /** + * How should the content be styled, by default + * this will emphasize the title + */ + textStyle?: 'normal' | 'reverse'; + /** + * How each item should be laid out + */ + type?: EuiDescriptionListType; + /** + * Props object to be passed to `EuiDescriptionListTitle` + */ + titleProps?: HTMLAttributes & CommonProps; + /** + * Props object to be passed to `EuiDescriptionListDescription` + */ + descriptionProps?: HTMLAttributes & CommonProps; +} + +export const TYPES = ['row', 'inline', 'column', 'responsiveColumn'] as const; +export type EuiDescriptionListType = typeof TYPES[number]; + +export const ALIGNMENTS = ['center', 'left'] as const; +export type EuiDescriptionListAlignment = typeof ALIGNMENTS[number]; + +export const TEXT_STYLES = ['normal', 'reverse'] as const; +export type EuiDescriptionListTextStyle = typeof TEXT_STYLES[number]; diff --git a/src/components/description_list/index.ts b/src/components/description_list/index.ts index 74a7d5b431d..ce7cf641b7a 100644 --- a/src/components/description_list/index.ts +++ b/src/components/description_list/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -export type { EuiDescriptionListProps } from './description_list'; +export type { EuiDescriptionListProps } from './description_list_types'; export { EuiDescriptionList } from './description_list'; export { EuiDescriptionListTitle } from './description_list_title'; diff --git a/src/components/index.scss b/src/components/index.scss index 98860729b2f..62dd466802f 100644 --- a/src/components/index.scss +++ b/src/components/index.scss @@ -15,7 +15,6 @@ @import 'control_bar/index'; @import 'date_picker/index'; @import 'datagrid/index'; -@import 'description_list/index'; @import 'drag_and_drop/index'; @import 'empty_prompt/index'; @import 'filter_group/index'; diff --git a/upcoming_changelogs/5971.md b/upcoming_changelogs/5971.md new file mode 100644 index 00000000000..7ec86c4d8c5 --- /dev/null +++ b/upcoming_changelogs/5971.md @@ -0,0 +1,4 @@ + +**CSS-in-JS conversions** + +- Converted `EuiDescriptionList` to Emotion \ No newline at end of file