diff --git a/src-docs/src/views/comment/comment_flexible.tsx b/src-docs/src/views/comment/comment_flexible.tsx index 06733166fbd..4af633f7ae5 100644 --- a/src-docs/src/views/comment/comment_flexible.tsx +++ b/src-docs/src/views/comment/comment_flexible.tsx @@ -11,8 +11,12 @@ import { EuiFlexItem, EuiSpacer, EuiCommentListProps, + EuiSelect, + EuiCode, } from '../../../../src/components/'; +import { EuiCommentEventProps } from '../../../../src/components/comment_list/comment_event'; + const body = (

@@ -64,14 +68,6 @@ const commentsData: EuiCommentListProps['comments'] = [ eventIconAriaLabel: 'tag', actions: copyAction, }, - { - username: 'system', - timelineAvatarAriaLabel: 'System', - timelineAvatar: 'dot', - event: 'pushed a new incident', - timestamp: '20 hours ago', - eventColor: 'danger', - }, { username: 'pancho1', timelineAvatarAriaLabel: 'Pancho PĂ©rez', @@ -95,10 +91,6 @@ const toggleButtons = [ id: 'update', label: 'Update', }, - { - id: 'updateDanger', - label: 'Update danger', - }, { id: 'custom', label: 'Custom', @@ -106,7 +98,22 @@ const toggleButtons = [ ]; export default () => { + const colors: Array<{ + value: EuiCommentEventProps['eventColor']; + text: string; + }> = [ + { value: 'subdued', text: 'subdued' }, + { value: 'transparent', text: 'transparent' }, + { value: 'plain', text: 'plain' }, + { value: 'danger', text: 'danger' }, + { value: 'warning', text: 'warning' }, + { value: 'accent', text: 'accent' }, + { value: 'primary', text: 'primary' }, + { value: 'success', text: 'success' }, + { value: undefined, text: 'undefined' }, + ]; const [toggleIdSelected, setToggleIdSelected] = useState('regular'); + const [color, setColor] = useState(colors[0].value); const [comment, setComment] = useState(commentsData[0]); const onChangeButtonGroup = (optionId: any) => { @@ -119,19 +126,57 @@ export default () => { setComment(commentsData[selectedCommentIndex]); }; + const onChangeSize = (e: React.ChangeEvent) => { + const color = e.target.value; + setColor( + color && color !== 'undefined' + ? (color as EuiCommentEventProps['eventColor']) + : undefined + ); + }; + return ( <> - + + + + + {toggleIdSelected !== 'custom' ? ( + + onChangeSize(e)} + compressed + /> + + ) : undefined} + + {toggleIdSelected === 'regular' && color === 'subdued' && ( + + subdued is the default eventColor for regular{' '} + EuiComment + + )} + {toggleIdSelected === 'update' && color === 'transparent' && ( + + transparent is the default eventColor for + update EuiComment + + )} + + - + ); diff --git a/src-docs/src/views/comment/comment_list.tsx b/src-docs/src/views/comment/comment_list.tsx index 82d0c5640c2..3e92e1d4292 100644 --- a/src-docs/src/views/comment/comment_list.tsx +++ b/src-docs/src/views/comment/comment_list.tsx @@ -41,19 +41,6 @@ const complexEvent = ( ); -const longBody = ( - -

- This planet has - or rather had - a problem, which was this: most of the - people living on it were unhappy for pretty much of the time. Many - solutions were suggested for this problem, but most of these were largely - concerned with the movements of small green pieces of paper, which is odd - because on the whole it was not the small green pieces of paper that were - unhappy. -

-
-); - const comments: EuiCommentProps[] = [ { username: 'janed', @@ -88,12 +75,12 @@ const comments: EuiCommentProps[] = [ eventIconAriaLabel: 'tag', }, { - username: 'elohar', - timelineAvatarAriaLabel: 'Elohar Jackson', - event: 'added a comment', - timestamp: 'on Jan 14, 2020', - children: longBody, + username: 'Assistant', + timelineAvatarAriaLabel: 'Assistant', + timestamp: 'on Jan 14, 2020, 1:39:04 PM', + children:

An error ocurred sending your message.

, actions: copyAction, + eventColor: 'danger', }, ]; diff --git a/src/components/comment_list/__snapshots__/comment.test.tsx.snap b/src/components/comment_list/__snapshots__/comment.test.tsx.snap index e955ed2877c..8ade678a2de 100644 --- a/src/components/comment_list/__snapshots__/comment.test.tsx.snap +++ b/src/components/comment_list/__snapshots__/comment.test.tsx.snap @@ -29,7 +29,7 @@ exports[`EuiComment is rendered 1`] = ` class="emotion-euiTimelineItemEvent-center" >
@@ -63,14 +63,14 @@ exports[`EuiComment props event is rendered 1`] = ` class="emotion-euiTimelineItemEvent-center" >
`; exports[`EuiCommentEvent props eventIcon and eventIconAriaLabel are rendered 1`] = `
@@ -72,7 +72,7 @@ exports[`EuiCommentList props gutterSize l is rendered 1`] = ` class="emotion-euiTimelineItemEvent-center" >
@@ -111,7 +111,7 @@ exports[`EuiCommentList props gutterSize m is rendered 1`] = ` class="emotion-euiTimelineItemEvent-center" >
@@ -150,7 +150,7 @@ exports[`EuiCommentList props gutterSize xl is rendered 1`] = ` class="emotion-euiTimelineItemEvent-center" >
diff --git a/src/components/comment_list/comment_event.stories.tsx b/src/components/comment_list/comment_event.stories.tsx new file mode 100644 index 00000000000..9a4ee0c8cb5 --- /dev/null +++ b/src/components/comment_list/comment_event.stories.tsx @@ -0,0 +1,86 @@ +/* + * 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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; + +import { EuiButtonIcon } from '../button'; +import { EuiCommentEvent, EuiCommentEventProps } from './comment_event'; + +const meta: Meta = { + title: 'EuiCommentEvent', + component: EuiCommentEvent, + args: { + username: 'janed', + }, + argTypes: { + eventColor: { + options: [ + undefined, + 'subdued', + 'transparent', + 'plain', + 'warning', + 'danger', + 'success', + 'primary', + 'accent', + ], + control: { type: 'radio' }, + defaultValue: undefined, + }, + actions: { + control: 'radio', + options: ['Example action', 'No actions'], + mapping: { + 'Example action': ( + + ), + 'No actions': null, + }, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Regular: Story = { + args: { + event: 'added a comment', + eventIcon: 'faceHappy', + eventIconAriaLabel: 'Happy face comment icon', + timestamp: 'on Jan 1, 2020', + actions: 'Example action', + children: + 'Far out in the uncharted backwaters of the unfashionable end of the western spiral arm of the Galaxy lies a small unregarded yellow sun.', + }, +}; + +export const Update: Story = { + args: { + event: 'added a comment', + eventIcon: 'faceHappy', + eventIconAriaLabel: 'Happy face comment icon', + timestamp: 'on Jan 1, 2020', + actions: 'Example action', + }, +}; + +export const Custom: Story = { + args: { + actions: 'No actions', + children: + 'No header or wrapper should appear if no event, icon, timestamp, or actions are passed', + }, +}; diff --git a/src/components/comment_list/comment_event.styles.ts b/src/components/comment_list/comment_event.styles.ts index de9acc41bde..42530c43101 100644 --- a/src/components/comment_list/comment_event.styles.ts +++ b/src/components/comment_list/comment_event.styles.ts @@ -7,66 +7,98 @@ */ import { css } from '@emotion/react'; -import { UseEuiTheme } from '../../services'; +import { UseEuiTheme, tintOrShade } from '../../services'; import { logicalCSS } from '../../global_styling'; -export const euiCommentEventStyles = ({ euiTheme }: UseEuiTheme) => ({ - euiCommentEvent: css` - overflow: hidden; - `, - // types - regular: css` - border: ${euiTheme.border.thin}; - border-radius: ${euiTheme.border.radius.medium}; - `, - update: css``, - custom: css``, -}); +export const euiCommentEventBorderColors = ({ + euiTheme, + colorMode, +}: UseEuiTheme) => { + const ratio = 0.6; + return { + warning: css` + border-color: ${tintOrShade(euiTheme.colors.warning, 0.4, colorMode)}; + `, + accent: css` + border-color: ${tintOrShade(euiTheme.colors.accent, ratio, colorMode)}; + `, + primary: css` + border-color: ${tintOrShade(euiTheme.colors.primary, ratio, colorMode)}; + `, + success: css` + border-color: ${tintOrShade(euiTheme.colors.success, ratio, colorMode)}; + `, + danger: css` + border-color: ${tintOrShade(euiTheme.colors.danger, ratio, colorMode)}; + `, + subdued: css` + border-color: ${euiTheme.border.color}; + `, + transparent: css` + border-color: ${euiTheme.border.color}; + `, + plain: css` + border-color: ${euiTheme.border.color}; + `, + }; +}; -export const euiCommentEventHeaderStyles = ({ euiTheme }: UseEuiTheme) => ({ - euiCommentEvent__header: css``, - // types - regular: css` - background: ${euiTheme.colors.lightestShade}; - ${logicalCSS('border-bottom', euiTheme.border.thin)} - padding: ${euiTheme.size.s}; - `, - // variants - hasEventColor: css` - padding: 0; - `, - // Children - euiCommentEvent__headerMain: css` - display: flex; - flex: 1; - gap: ${euiTheme.size.s}; - `, - euiCommentEvent__headerData: css` - display: flex; - flex: 1; - align-items: center; - flex-wrap: wrap; - gap: ${euiTheme.size.xs}; - `, - euiCommentEvent__headerEventIcon: css` - ${logicalCSS('margin-right', euiTheme.size.xs)} - `, - euiCommentEvent__headerUsername: css` - font-weight: ${euiTheme.font.weight.semiBold}; - `, - euiCommentEvent__headerEvent: css` - align-items: center; - display: inline-flex; - /* the header event can have inline badges so we're adding some white-space and flex-wrap properties */ - white-space: pre-wrap; - flex-wrap: wrap; - `, - euiCommentEvent__headerActions: css` - display: flex; - flex-wrap: wrap; - gap: ${euiTheme.size.xs}; - `, -}); +export const euiCommentEventStyles = (euiThemeContext: UseEuiTheme) => { + const { euiTheme } = euiThemeContext; + return { + euiCommentEvent: css` + overflow: hidden; + `, + border: css` + border-width: ${euiTheme.border.width.thin}; + border-style: solid; + border-radius: ${euiTheme.border.radius.medium}; + `, + }; +}; + +export const euiCommentEventHeaderStyles = (euiThemeContext: UseEuiTheme) => { + const { euiTheme } = euiThemeContext; + + return { + euiCommentEvent__header: css``, + border: css` + ${logicalCSS('border-bottom-style', 'solid')} + ${logicalCSS('border-bottom-width', euiTheme.border.width.thin)} + `, + // Children + euiCommentEvent__headerMain: css` + display: flex; + flex: 1; + gap: ${euiTheme.size.s}; + `, + euiCommentEvent__headerData: css` + display: flex; + flex: 1; + align-items: center; + flex-wrap: wrap; + gap: ${euiTheme.size.xs}; + `, + euiCommentEvent__headerEventIcon: css` + ${logicalCSS('margin-right', euiTheme.size.xs)} + `, + euiCommentEvent__headerUsername: css` + font-weight: ${euiTheme.font.weight.semiBold}; + `, + euiCommentEvent__headerEvent: css` + align-items: center; + display: inline-flex; + /* the header event can have inline badges so we're adding some white-space and flex-wrap properties */ + white-space: pre-wrap; + flex-wrap: wrap; + `, + euiCommentEvent__headerActions: css` + display: flex; + flex-wrap: wrap; + gap: ${euiTheme.size.xs}; + `, + }; +}; export const euiCommentEventBodyStyles = ({ euiTheme }: UseEuiTheme) => ({ euiCommentEvent__body: css``, diff --git a/src/components/comment_list/comment_event.tsx b/src/components/comment_list/comment_event.tsx index 177a5534c22..4747e3910c9 100644 --- a/src/components/comment_list/comment_event.tsx +++ b/src/components/comment_list/comment_event.tsx @@ -6,14 +6,17 @@ * Side Public License, v 1. */ -import React, { FunctionComponent, ReactNode } from 'react'; -import { CommonProps } from '../common'; -import { useEuiTheme } from '../../services'; +import React, { FunctionComponent, ReactNode, useMemo } from 'react'; import classNames from 'classnames'; + +import { useEuiTheme } from '../../services'; +import { CommonProps } from '../common'; import { IconType } from '../icon'; import { EuiPanel, EuiPanelProps } from '../panel'; import { EuiAvatar } from '../avatar'; + import { + euiCommentEventBorderColors, euiCommentEventStyles, euiCommentEventHeaderStyles, euiCommentEventBodyStyles, @@ -69,6 +72,9 @@ export const EuiCommentEvent: FunctionComponent = ({ }) => { const classes = classNames('euiCommentEvent', className); + /** + * Branching logic + */ // the username is required so we only check if other elements are define const hasEventElements = eventIcon || timestamp || event || actions; @@ -87,34 +93,51 @@ export const EuiCommentEvent: FunctionComponent = ({ type = 'custom'; } + if (isTypeRegular && !eventColor) { + eventColor = 'subdued'; + } + if (isTypeUpdate && !eventColor) { + eventColor = 'transparent'; + } + const showEventBorders = isTypeRegular; + + const panelProps: EuiPanelProps = useMemo( + () => ({ + color: type === 'custom' ? 'transparent' : eventColor, + paddingSize: type === 'custom' ? 'none' : 's', + borderRadius: type === 'regular' ? 'none' : 'm', + hasShadow: false, // `plain` color needs this + }), + [type, eventColor] + ); + + const isFigure = isTypeRegular; + const Element = isFigure ? 'figure' : 'div'; + const HeaderElement = isFigure ? 'figcaption' : 'div'; + + /** + * Styles + */ const euiTheme = useEuiTheme(); + const borderStyles = euiCommentEventBorderColors(euiTheme); const styles = euiCommentEventStyles(euiTheme); - const cssStyles = [styles.euiCommentEvent, styles[type]]; + const cssStyles = [ + styles.euiCommentEvent, + showEventBorders && styles.border, + showEventBorders && borderStyles[eventColor!], + ]; const headerStyles = euiCommentEventHeaderStyles(euiTheme); const cssHeaderStyles = [ headerStyles.euiCommentEvent__header, - eventColor && headerStyles.hasEventColor, - isTypeRegular && headerStyles.regular, + showEventBorders && headerStyles.border, + showEventBorders && borderStyles[eventColor!], ]; const bodyStyles = euiCommentEventBodyStyles(euiTheme); const cssBodyStyles = [bodyStyles.euiCommentEvent__body, bodyStyles[type]]; - const isFigure = isTypeRegular; - - const Element = isFigure ? 'figure' : 'div'; - const HeaderElement = isFigure ? 'figcaption' : 'div'; - - // The 'plain' color creates a shadow and adds a border radius that we don't want. - // So for these cases we use the transparent color instead. - const finalEventColor = eventColor === 'plain' ? 'transparent' : eventColor; - - const panelProps = finalEventColor - ? { color: finalEventColor, paddingSize: 's' } - : { color: 'transparent', paddingSize: 'none' }; - return ( {hasEventElements && ( @@ -122,7 +145,7 @@ export const EuiCommentEvent: FunctionComponent = ({ className="euiCommentEvent__header" css={cssHeaderStyles} > - +