From e818cfa0c645a5339860c64da578f4bb2d5dd8a9 Mon Sep 17 00:00:00 2001 From: Kyriakos Date: Tue, 5 Sep 2023 11:23:00 +0200 Subject: [PATCH 01/19] add dismissible behavior --- src/components/call_out/call_out.styles.ts | 13 ++++++- src/components/call_out/call_out.tsx | 45 +++++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/components/call_out/call_out.styles.ts b/src/components/call_out/call_out.styles.ts index df020758a0f..611a5699094 100644 --- a/src/components/call_out/call_out.styles.ts +++ b/src/components/call_out/call_out.styles.ts @@ -12,7 +12,18 @@ import { UseEuiTheme } from '../../services'; export const euiCallOutStyles = ({ euiTheme }: UseEuiTheme) => { return { - euiCallOut: css``, + euiCallOut: css` + position: relative; + `, + euiCallOut__dismissButton: css` + ${logicalCSS('margin-left', euiTheme.size.s)} + `, + euiCallOut__closeIcon: css` + position: absolute; + ${logicalCSS('top', euiTheme.size.s)} + ${logicalCSS('right', euiTheme.size.s)} + cursor: pointer; + `, euiCallOut__icon: css` position: relative; ${logicalCSS('top', '-1px')} diff --git a/src/components/call_out/call_out.tsx b/src/components/call_out/call_out.tsx index ea25ab23e43..92d3edc2478 100644 --- a/src/components/call_out/call_out.tsx +++ b/src/components/call_out/call_out.tsx @@ -13,6 +13,7 @@ import classNames from 'classnames'; import { CommonProps } from '../common'; import { IconType, EuiIcon } from '../icon'; +import { EuiButton, EuiButtonEmpty, EuiButtonIcon } from '../button'; import { EuiText } from '../text'; import { useEuiTheme } from '../../services'; import { EuiPanel } from '../panel'; @@ -35,6 +36,8 @@ export type EuiCallOutProps = CommonProps & color?: Color; size?: Size; heading?: Heading; + onClose?: () => void; //function to handle dismiss action + isDismissible?: boolean; }; export const EuiCallOut = forwardRef( @@ -47,6 +50,8 @@ export const EuiCallOut = forwardRef( children, className, heading = 'p', + onClose, + isDismissible = true, ...rest }, ref @@ -54,6 +59,8 @@ export const EuiCallOut = forwardRef( const theme = useEuiTheme(); const styles = euiCallOutStyles(theme); const cssStyles = [styles.euiCallOut]; + const cssCloseIconStyle = [styles.euiCallOut__closeIcon]; + const cssDismissButtonStyle = [styles.euiCallOut__dismissButton]; const cssIconStyle = [styles.euiCallOut__icon]; const cssDescriptionStyle = [styles.euiCallOut__description]; @@ -71,6 +78,22 @@ export const EuiCallOut = forwardRef( className ); + const closeIcon = isDismissible ? ( + + ) : null; + + const dismissButton = isDismissible ? ( + + Dismiss + + ) : null; + let headerIcon; if (iconType) { @@ -84,9 +107,16 @@ export const EuiCallOut = forwardRef( /> ); } - + let hasButtonInChildren = false; + let isChildren = false; let optionalChildren; if (children) { + // Check if children contains any EuiButton components + isDismissible && + (hasButtonInChildren = React.Children.toArray(children).some( + (child) => React.isValidElement(child) && child.type === EuiButton + )); + isChildren = true; optionalChildren = ( ( color="default" > {children} + {hasButtonInChildren ? ( + + Dismiss + + ) : ( + dismissButton + )} ); } @@ -122,9 +163,11 @@ export const EuiCallOut = forwardRef( grow={false} {...rest} > + {closeIcon} {header} {optionalChildren} + {!isChildren && dismissButton} ); } From a055e7903d7a81952d986e8e56c73d06579a39b2 Mon Sep 17 00:00:00 2001 From: Kyriakos Date: Tue, 5 Sep 2023 11:35:08 +0200 Subject: [PATCH 02/19] add isDismissible --- .../__snapshots__/call_out.test.tsx.snap | 400 +++++++++++++++++- .../form/__snapshots__/form.test.tsx.snap | 78 ++++ 2 files changed, 466 insertions(+), 12 deletions(-) diff --git a/src/components/call_out/__snapshots__/call_out.test.tsx.snap b/src/components/call_out/__snapshots__/call_out.test.tsx.snap index 0813a304ab7..acc0e734c8f 100644 --- a/src/components/call_out/__snapshots__/call_out.test.tsx.snap +++ b/src/components/call_out/__snapshots__/call_out.test.tsx.snap @@ -6,10 +6,36 @@ exports[`EuiCallOut is rendered 1`] = ` class="euiPanel euiPanel--primary euiPanel--paddingMedium euiCallOut euiCallOut--primary testClass1 testClass2 emotion-euiPanel-none-m-primary-euiCallOut-euiTestCss" data-test-subj="test subject string" > +
Content +
`; @@ -17,79 +43,415 @@ exports[`EuiCallOut is rendered 1`] = ` exports[`EuiCallOut props color danger is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props color primary is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props color success is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props color warning is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props heading h1 is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props heading h2 is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props heading h3 is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props heading h4 is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props heading h5 is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props heading h6 is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props heading p is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props iconType is rendered 1`] = `
+> + + +
`; exports[`EuiCallOut props title is rendered 1`] = `
+

@@ -99,6 +461,20 @@ exports[`EuiCallOut props title is rendered 1`] = ` class="euiText emotion-euiText-s-euiTextColor-default-euiCallOut__description" > Content +

`; diff --git a/src/components/form/__snapshots__/form.test.tsx.snap b/src/components/form/__snapshots__/form.test.tsx.snap index f95020e3136..142ff8edd51 100644 --- a/src/components/form/__snapshots__/form.test.tsx.snap +++ b/src/components/form/__snapshots__/form.test.tsx.snap @@ -28,11 +28,37 @@ exports[`EuiForm renders with error callout when isInvalid is "true" 1`] = ` role="alert" tabindex="-1" > +

Please address the highlighted errors.

+ `; @@ -49,6 +75,18 @@ exports[`EuiForm renders with error callout when isInvalid is "true" and has mul role="alert" tabindex="-1" > +

@@ -73,6 +111,20 @@ exports[`EuiForm renders with error callout when isInvalid is "true" and has mul + @@ -90,6 +142,18 @@ exports[`EuiForm renders with error callout when isInvalid is "true" and has one role="alert" tabindex="-1" > +

@@ -107,6 +171,20 @@ exports[`EuiForm renders with error callout when isInvalid is "true" and has one + From bbf3fa8fcbab90231c8700f064d5c3006d43fb8a Mon Sep 17 00:00:00 2001 From: Kyriakos Date: Tue, 5 Sep 2023 15:40:41 +0200 Subject: [PATCH 03/19] refactor --- src/components/call_out/call_out.styles.ts | 18 +- src/components/call_out/call_out.tsx | 207 +++++++++++++-------- 2 files changed, 147 insertions(+), 78 deletions(-) diff --git a/src/components/call_out/call_out.styles.ts b/src/components/call_out/call_out.styles.ts index 611a5699094..b869f6b9351 100644 --- a/src/components/call_out/call_out.styles.ts +++ b/src/components/call_out/call_out.styles.ts @@ -15,9 +15,6 @@ export const euiCallOutStyles = ({ euiTheme }: UseEuiTheme) => { euiCallOut: css` position: relative; `, - euiCallOut__dismissButton: css` - ${logicalCSS('margin-left', euiTheme.size.s)} - `, euiCallOut__closeIcon: css` position: absolute; ${logicalCSS('top', euiTheme.size.s)} @@ -33,6 +30,19 @@ export const euiCallOutStyles = ({ euiTheme }: UseEuiTheme) => { :not(:only-child) { ${logicalCSS('margin-top', euiTheme.size.s)} } + + .euiButtonEmpty:last-child { + ${logicalCSS('margin-left', euiTheme.size.s)} + } + `, + euiCallOut__dismissButton_isLast: css` + ${logicalCSS('margin-left', euiTheme.size.s)} + `, + euiCallOut__title_verticalSpace: css` + margin-block-end: ${parseInt(euiTheme.size.xxl) / 2}px !important; + `, + euiCallOut__title_endSpace: css` + padding-inline-end: ${euiTheme.size.l}; `, }; }; @@ -43,7 +53,7 @@ export const euiCallOutHeadingStyles = ({ euiTheme }: UseEuiTheme) => { font-weight: ${euiTheme.font.weight.medium}; ${logicalCSS( 'margin-bottom', - '0 !important' + '0' // In case it's nested inside EuiText )} `, diff --git a/src/components/call_out/call_out.tsx b/src/components/call_out/call_out.tsx index 92d3edc2478..35ed31de3e4 100644 --- a/src/components/call_out/call_out.tsx +++ b/src/components/call_out/call_out.tsx @@ -6,7 +6,12 @@ * Side Public License, v 1. */ -import React, { forwardRef, HTMLAttributes, ReactNode } from 'react'; +import React, { + forwardRef, + FunctionComponent, + HTMLAttributes, + ReactNode, +} from 'react'; import classNames from 'classnames'; @@ -18,6 +23,7 @@ import { EuiText } from '../text'; import { useEuiTheme } from '../../services'; import { EuiPanel } from '../panel'; import { EuiTitle } from '../title'; +import { EuiI18n } from '../i18n'; import { euiCallOutStyles, euiCallOutHeadingStyles } from './call_out.styles'; @@ -36,10 +42,71 @@ export type EuiCallOutProps = CommonProps & color?: Color; size?: Size; heading?: Heading; - onClose?: () => void; //function to handle dismiss action + onClose?: ( + event?: + | React.KeyboardEvent + | React.MouseEvent + ) => void; //function to handle dismiss action isDismissible?: boolean; }; +type DismissButtonProps = { + hasButtonInChildren: boolean; + onClose?: ( + event?: + | React.KeyboardEvent + | React.MouseEvent + ) => void; //function to handle dismiss action + color: Color; +}; + +type CallOutHeaderProps = { + title?: ReactNode; + headerIcon?: ReactNode; + heading: Heading; + size: 's' | 'm'; + cssHeaderStyles: any; +}; + +const DismissButton: FunctionComponent = ({ + hasButtonInChildren, + onClose, + color, +}) => { + if (hasButtonInChildren) { + return ( + + Dismiss + + ); + } + return ( + + Dismiss + + ); +}; + +const CallOutHeader: FunctionComponent = ({ + title, + headerIcon, + heading, + size, + cssHeaderStyles, +}) => { + if (!title) return null; + + const H: Heading = heading; + return ( + + + {headerIcon} + {title} + + + ); +}; + export const EuiCallOut = forwardRef( ( { @@ -60,7 +127,9 @@ export const EuiCallOut = forwardRef( const styles = euiCallOutStyles(theme); const cssStyles = [styles.euiCallOut]; const cssCloseIconStyle = [styles.euiCallOut__closeIcon]; - const cssDismissButtonStyle = [styles.euiCallOut__dismissButton]; + const cssTitleVerticalSpaceStyle = [styles.euiCallOut__title_verticalSpace]; + const cssTitleEndStyle = [styles.euiCallOut__title_endSpace]; + const cssIconStyle = [styles.euiCallOut__icon]; const cssDescriptionStyle = [styles.euiCallOut__description]; @@ -78,79 +147,54 @@ export const EuiCallOut = forwardRef( className ); + const hasButtonInChildren = React.Children.toArray(children).some( + (child) => React.isValidElement(child) && child.type === EuiButton + ); + const closeIcon = isDismissible ? ( - + + {(closeCallOut: string) => ( + + )} + ) : null; - const dismissButton = isDismissible ? ( - - Dismiss - - ) : null; + const headerIcon = iconType && ( +

Title

@@ -461,20 +279,6 @@ exports[`EuiCallOut props title is rendered 1`] = ` class="euiText emotion-euiText-s-euiTextColor-default-euiCallOut__description" > Content - `; diff --git a/src/components/call_out/call_out.styles.ts b/src/components/call_out/call_out.styles.ts index 05ec2063fe9..d4ecd99b8f7 100644 --- a/src/components/call_out/call_out.styles.ts +++ b/src/components/call_out/call_out.styles.ts @@ -31,9 +31,6 @@ export const euiCallOutStyles = ({ euiTheme }: UseEuiTheme) => { ${logicalCSS('margin-top', euiTheme.size.s)} } `, - euiCallOut__title_endSpace: css` - padding-inline-end: ${euiTheme.size.l}; - `, }; }; @@ -47,6 +44,9 @@ export const euiCallOutHeadingStyles = ({ euiTheme }: UseEuiTheme) => { // @ts-ignore In case it's nested inside EuiText )} `, + euiCallOutHeader_endSpace: css` + padding-inline-end: ${euiTheme.size.l}; + `, primary: css` color: ${euiTheme.colors.primaryText}; `, diff --git a/src/components/call_out/call_out.tsx b/src/components/call_out/call_out.tsx index 9c210e4419f..6c3b13d55b9 100644 --- a/src/components/call_out/call_out.tsx +++ b/src/components/call_out/call_out.tsx @@ -37,11 +37,7 @@ export type EuiCallOutProps = CommonProps & color?: Color; size?: Size; heading?: Heading; - onClose?: ( - event?: - | React.KeyboardEvent - | React.MouseEvent - ) => void; + onClose?: () => void; isDismissible?: boolean; }; @@ -65,12 +61,12 @@ export const EuiCallOut = forwardRef( const styles = euiCallOutStyles(theme); const cssStyles = [styles.euiCallOut]; const cssCloseIconStyle = [styles.euiCallOut__closeIcon]; - const cssTitleEndStyle = [styles.euiCallOut__title_endSpace]; const cssIconStyle = [styles.euiCallOut__icon]; const cssDescriptionStyle = [styles.euiCallOut__description]; const headerStyles = euiCallOutHeadingStyles(theme); + const cssHeaderEndStyle = [headerStyles.euiCallOutHeader_endSpace]; const cssHeaderStyles = [ headerStyles.euiCallOutHeader, headerStyles[color], @@ -111,7 +107,7 @@ export const EuiCallOut = forwardRef( const header = title ? ( {headerIcon} diff --git a/src/components/form/__snapshots__/form.test.tsx.snap b/src/components/form/__snapshots__/form.test.tsx.snap index 142ff8edd51..fb52d710097 100644 --- a/src/components/form/__snapshots__/form.test.tsx.snap +++ b/src/components/form/__snapshots__/form.test.tsx.snap @@ -41,24 +41,10 @@ exports[`EuiForm renders with error callout when isInvalid is "true" 1`] = ` />

Please address the highlighted errors.

- `; @@ -88,7 +74,7 @@ exports[`EuiForm renders with error callout when isInvalid is "true" and has mul />

Please address the highlighted errors.

@@ -111,20 +97,6 @@ exports[`EuiForm renders with error callout when isInvalid is "true" and has mul - @@ -155,7 +127,7 @@ exports[`EuiForm renders with error callout when isInvalid is "true" and has one />

Please address the highlighted errors.

@@ -171,20 +143,6 @@ exports[`EuiForm renders with error callout when isInvalid is "true" and has one - From 0533b24b37fdf8c49d9ca06618e3c0468d9f6014 Mon Sep 17 00:00:00 2001 From: Kyriakos Spiliotopoulos <92029479+kyrspl@users.noreply.github.com> Date: Tue, 19 Sep 2023 17:43:44 +0200 Subject: [PATCH 10/19] Update src/components/call_out/call_out.tsx Co-authored-by: Bree Hall <40739624+breehall@users.noreply.github.com> --- src/components/call_out/call_out.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/call_out/call_out.tsx b/src/components/call_out/call_out.tsx index 6c3b13d55b9..2403d9aef63 100644 --- a/src/components/call_out/call_out.tsx +++ b/src/components/call_out/call_out.tsx @@ -38,7 +38,6 @@ export type EuiCallOutProps = CommonProps & size?: Size; heading?: Heading; onClose?: () => void; - isDismissible?: boolean; }; export const EuiCallOut = forwardRef( From ed63118e03ce443e2c82160e044a5d6270f5f011 Mon Sep 17 00:00:00 2001 From: Kyriakos Spiliotopoulos <92029479+kyrspl@users.noreply.github.com> Date: Tue, 19 Sep 2023 17:44:38 +0200 Subject: [PATCH 11/19] Update src/components/call_out/call_out.tsx --- src/components/call_out/call_out.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/call_out/call_out.tsx b/src/components/call_out/call_out.tsx index 2403d9aef63..4beffb3495d 100644 --- a/src/components/call_out/call_out.tsx +++ b/src/components/call_out/call_out.tsx @@ -79,7 +79,7 @@ export const EuiCallOut = forwardRef( className ); - const closeIcon = isDismissible ? ( + const closeIcon = onClose ? ( {(closeCallOut: string) => ( Date: Tue, 19 Sep 2023 17:45:01 +0200 Subject: [PATCH 12/19] Update src/components/call_out/call_out.tsx --- src/components/call_out/call_out.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/call_out/call_out.tsx b/src/components/call_out/call_out.tsx index 4beffb3495d..f542e3bb6f0 100644 --- a/src/components/call_out/call_out.tsx +++ b/src/components/call_out/call_out.tsx @@ -106,7 +106,7 @@ export const EuiCallOut = forwardRef( const header = title ? ( {headerIcon} From 5bd944690b153300ab1a05e8ce1b0e0200b30f10 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 22 Sep 2023 17:07:53 -0700 Subject: [PATCH 13/19] [PR feedback] Prop name/copy Switch from `close` copy to `dismiss`, which better matches other similar components (e.g. EuiToast uses `dismissToast`) --- src/components/call_out/call_out.tsx | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/components/call_out/call_out.tsx b/src/components/call_out/call_out.tsx index f542e3bb6f0..df21ead0f46 100644 --- a/src/components/call_out/call_out.tsx +++ b/src/components/call_out/call_out.tsx @@ -37,7 +37,14 @@ export type EuiCallOutProps = CommonProps & color?: Color; size?: Size; heading?: Heading; - onClose?: () => void; + /** + * Passing an `onDismiss` callback will render a cross in the top right hand corner + * of the callout. + * + * This callback fires when users click this button, which allows conditionally + * removing the callout or other actions. + */ + onDismiss?: () => void; }; export const EuiCallOut = forwardRef( @@ -50,8 +57,7 @@ export const EuiCallOut = forwardRef( children, className, heading = 'p', - onClose, - isDismissible = true, + onDismiss, ...rest }, ref @@ -79,13 +85,13 @@ export const EuiCallOut = forwardRef( className ); - const closeIcon = onClose ? ( - - {(closeCallOut: string) => ( + const dismissButton = onDismiss ? ( + + {(dismissAriaLabel: string) => ( @@ -136,7 +142,7 @@ export const EuiCallOut = forwardRef( grow={false} {...rest} > - {closeIcon} + {dismissButton} {header} {optionalChildren} From 8b4cd06be91922beb87194f7eb2e5d263999bd5a Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 22 Sep 2023 17:13:09 -0700 Subject: [PATCH 14/19] Add Jest unit test --- src/components/call_out/call_out.test.tsx | 11 +++++++++++ src/components/call_out/call_out.tsx | 1 + 2 files changed, 12 insertions(+) diff --git a/src/components/call_out/call_out.test.tsx b/src/components/call_out/call_out.test.tsx index 4e05b690aed..50c992e2319 100644 --- a/src/components/call_out/call_out.test.tsx +++ b/src/components/call_out/call_out.test.tsx @@ -7,6 +7,7 @@ */ import React from 'react'; +import { fireEvent } from '@testing-library/react'; import { requiredProps } from '../../test/required_props'; import { render } from '../../test/rtl'; @@ -59,5 +60,15 @@ describe('EuiCallOut', () => { }); }); }); + + test('onDismiss', () => { + const onDismiss = jest.fn(); + const { getByTestSubject } = render( + Content + ); + + fireEvent.click(getByTestSubject('euiDismissCalloutButton')); + expect(onDismiss).toHaveBeenCalledTimes(1); + }); }); }); diff --git a/src/components/call_out/call_out.tsx b/src/components/call_out/call_out.tsx index df21ead0f46..ab2e982db85 100644 --- a/src/components/call_out/call_out.tsx +++ b/src/components/call_out/call_out.tsx @@ -94,6 +94,7 @@ export const EuiCallOut = forwardRef( aria-label={dismissAriaLabel} css={cssCloseIconStyle} color={color} + data-test-subj="euiDismissCalloutButton" /> )} From 6dc8363ba82939e601f3cedf0e3221729fd976c7 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 22 Sep 2023 17:35:58 -0700 Subject: [PATCH 15/19] Add docs example + playground --- .../src/views/call_out/call_out_example.js | 27 +++++++ src-docs/src/views/call_out/on_dismiss.tsx | 78 +++++++++++++++++++ src-docs/src/views/call_out/playground.js | 7 ++ 3 files changed, 112 insertions(+) create mode 100644 src-docs/src/views/call_out/on_dismiss.tsx diff --git a/src-docs/src/views/call_out/call_out_example.js b/src-docs/src/views/call_out/call_out_example.js index feda7223691..97f563aceb3 100644 --- a/src-docs/src/views/call_out/call_out_example.js +++ b/src-docs/src/views/call_out/call_out_example.js @@ -46,6 +46,15 @@ const dangerSnippet = [ `, ]; +import OnDismiss from './on_dismiss'; +const onDismissSource = require('!!raw-loader!./on_dismiss'); +const onDismissSnippet = [ + ` +

+
+`, +]; + export const CallOutExample = { title: 'Callout', intro: ( @@ -164,5 +173,23 @@ export const CallOutExample = { snippet: dangerSnippet, demo: , }, + { + title: 'Dismissible callouts', + source: [ + { + type: GuideSectionTypes.TSX, + code: onDismissSource, + }, + ], + text: ( +

+ To render a cross icon in the top right hand corner, pass an{' '} + onDismiss callback that handles conditionally + rendering your callout. +

+ ), + snippet: onDismissSnippet, + demo: , + }, ], }; diff --git a/src-docs/src/views/call_out/on_dismiss.tsx b/src-docs/src/views/call_out/on_dismiss.tsx new file mode 100644 index 00000000000..6c35f8fe33d --- /dev/null +++ b/src-docs/src/views/call_out/on_dismiss.tsx @@ -0,0 +1,78 @@ +import React, { useState } from 'react'; + +import { + EuiFlexGroup, + EuiSwitch, + EuiSpacer, + EuiButtonEmpty, + EuiCallOut, +} from '../../../../src'; + +export default () => { + const [showCallOut, setShowCallOut] = useState( + !localStorage.getItem('EuiCallOutOnDismissDemo') + ); + const onDismiss = () => { + setShowCallOut(false); + localStorage.setItem('EuiCallOutOnDismissDemo', 'hidden'); + }; + const resetDemo = () => { + setShowCallOut(true); + localStorage.setItem('EuiCallOutOnDismissDemo', ''); + }; + + // UI toggles + const [showTitle, setShowTitle] = useState(true); + const [showChildren, setShowChildren] = useState(true); + const [smallSize, setSmallSize] = useState(false); + + return ( +
+ + setShowTitle(e.target.checked)} + compressed + /> + setShowChildren(e.target.checked)} + compressed + /> + setSmallSize(e.target.checked)} + compressed + /> + + + {showCallOut ? ( + + {showChildren && ( +

+ Here’s more some stuff users need to know. But maybe users don't + need to know it on every page refresh, so you could remember + whether or not to display this callout in local storage. +

+ )} +
+ ) : ( + + The callout has been dismissed. Click to reset the demo + + )} +
+ ); +}; diff --git a/src-docs/src/views/call_out/playground.js b/src-docs/src/views/call_out/playground.js index d388ef32bd5..19847dd96de 100644 --- a/src-docs/src/views/call_out/playground.js +++ b/src-docs/src/views/call_out/playground.js @@ -3,6 +3,8 @@ import { EuiCallOut, EuiText } from '../../../../src/components/'; import { propUtilityForPlayground, iconValidator, + simulateFunction, + dummyFunction, } from '../../services/playground'; export default () => { @@ -29,6 +31,8 @@ export default () => { hidden: false, }; + propsToUse.onDismiss = simulateFunction(propsToUse.onDismiss); + return { config: { componentName: 'EuiCallOut', @@ -42,6 +46,9 @@ export default () => { named: ['EuiCallOut', 'EuiText'], }, }, + customProps: { + onDismiss: dummyFunction, + }, }, }; }; From de207f1da622d3fb5ea405e8a06dd7c97c73ea5c Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 22 Sep 2023 18:08:48 -0700 Subject: [PATCH 16/19] Fix various conditional style issues - Dismiss button should to adjust to callout size/padding - Fix padding-right logic on top-most title or child paragraph via CSS selectors - Fix non-working spacer logic (just use a JS conditional to render a spacer instead of CSS `:not:only-child`) - Fix button DOM order for screen reader users - misc `&&` vs ternary cleanup --- src-docs/src/views/call_out/on_dismiss.tsx | 18 +++++-- src/components/call_out/call_out.styles.ts | 46 ++++++++++------ src/components/call_out/call_out.tsx | 62 +++++++++++++--------- 3 files changed, 81 insertions(+), 45 deletions(-) diff --git a/src-docs/src/views/call_out/on_dismiss.tsx b/src-docs/src/views/call_out/on_dismiss.tsx index 6c35f8fe33d..9589ed012f9 100644 --- a/src-docs/src/views/call_out/on_dismiss.tsx +++ b/src-docs/src/views/call_out/on_dismiss.tsx @@ -61,11 +61,19 @@ export default () => { size={smallSize ? 's' : 'm'} > {showChildren && ( -

- Here’s more some stuff users need to know. But maybe users don't - need to know it on every page refresh, so you could remember - whether or not to display this callout in local storage. -

+ <> +

+ Here’s more some stuff users need to know. But maybe users don't + need to know it on every page refresh, so you could remember + whether or not to display this callout in local storage. +

+ {!showTitle && ( +

+ This second paragraph is here to demonstrate that only the + first one needs to account for the dismiss button in width. +

+ )} + )} ) : ( diff --git a/src/components/call_out/call_out.styles.ts b/src/components/call_out/call_out.styles.ts index d4ecd99b8f7..a6164f8d951 100644 --- a/src/components/call_out/call_out.styles.ts +++ b/src/components/call_out/call_out.styles.ts @@ -15,22 +15,41 @@ export const euiCallOutStyles = ({ euiTheme }: UseEuiTheme) => { euiCallOut: css` position: relative; `, - euiCallOut__closeIcon: css` - position: absolute; - ${logicalCSS('top', euiTheme.size.s)} - ${logicalCSS('right', euiTheme.size.s)} - cursor: pointer; - `, + hasDismissButton: { + // Ensure that only the top-most (first-child) title or child text + // has a padding-right on it (to account for the dismiss button) + hasDimissButton: css` + & > :first-child:is(.euiTitle), + & > :first-child:is(.euiText) > :first-child { + ${logicalCSS('padding-right', euiTheme.size.base)} + } + `, + // Ensure the callout always has enough height for the button + s: css` + ${logicalCSS('min-height', euiTheme.size.xl)} + `, + m: css` + ${logicalCSS('min-height', euiTheme.size.xxl)} + `, + }, + dismissButton: { + euiCallOut__dismissButton: css` + position: absolute; + `, + s: css` + ${logicalCSS('top', euiTheme.size.xs)} + ${logicalCSS('right', euiTheme.size.xs)} + `, + m: css` + ${logicalCSS('top', euiTheme.size.s)} + ${logicalCSS('right', euiTheme.size.s)} + `, + }, euiCallOut__icon: css` position: relative; ${logicalCSS('top', '-1px')} ${logicalCSS('margin-right', euiTheme.size.s)} `, - euiCallOut__description: css` - :not(:only-child) { - ${logicalCSS('margin-top', euiTheme.size.s)} - } - `, }; }; @@ -41,12 +60,9 @@ export const euiCallOutHeadingStyles = ({ euiTheme }: UseEuiTheme) => { ${logicalCSS( 'margin-bottom', '0 !important' - // @ts-ignore In case it's nested inside EuiText + // In case it's nested inside EuiText )} `, - euiCallOutHeader_endSpace: css` - padding-inline-end: ${euiTheme.size.l}; - `, primary: css` color: ${euiTheme.colors.primaryText}; `, diff --git a/src/components/call_out/call_out.tsx b/src/components/call_out/call_out.tsx index ab2e982db85..4c57e569bb0 100644 --- a/src/components/call_out/call_out.tsx +++ b/src/components/call_out/call_out.tsx @@ -17,6 +17,7 @@ import { EuiButtonIcon } from '../button'; import { EuiText } from '../text'; import { useEuiTheme } from '../../services'; import { EuiPanel } from '../panel'; +import { EuiSpacer } from '../spacer'; import { EuiTitle } from '../title'; import { EuiI18n } from '../i18n'; @@ -64,14 +65,16 @@ export const EuiCallOut = forwardRef( ) => { const theme = useEuiTheme(); const styles = euiCallOutStyles(theme); - const cssStyles = [styles.euiCallOut]; - const cssCloseIconStyle = [styles.euiCallOut__closeIcon]; - - const cssIconStyle = [styles.euiCallOut__icon]; - const cssDescriptionStyle = [styles.euiCallOut__description]; - + const cssStyles = [ + styles.euiCallOut, + onDismiss && styles.hasDismissButton.hasDimissButton, + onDismiss && styles.hasDismissButton[size], + ]; + const cssDismissButtonStyles = [ + styles.dismissButton.euiCallOut__dismissButton, + styles.dismissButton[size], + ]; const headerStyles = euiCallOutHeadingStyles(theme); - const cssHeaderEndStyle = [headerStyles.euiCallOutHeader_endSpace]; const cssHeaderStyles = [ headerStyles.euiCallOutHeader, headerStyles[color], @@ -85,24 +88,24 @@ export const EuiCallOut = forwardRef( className ); - const dismissButton = onDismiss ? ( + const dismissButton = onDismiss && ( {(dismissAriaLabel: string) => ( )} - ) : null; + ); const headerIcon = iconType && (