From e1139c048cfc642b81c032cd86a3786610877800 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Sat, 13 Jan 2024 20:15:35 -0400 Subject: [PATCH 01/17] Update EuiButtonGroup to use EuiTooltip instead of the default browser title attribute --- .../src/views/button/button_group_icon.js | 3 + .../button_group/button_group.styles.ts | 2 +- .../button/button_group/button_group.tsx | 17 ++++- .../button_group_button.styles.ts | 62 +++++++++++------- .../button_group/button_group_button.tsx | 65 +++++++++++++------ 5 files changed, 102 insertions(+), 47 deletions(-) diff --git a/src-docs/src/views/button/button_group_icon.js b/src-docs/src/views/button/button_group_icon.js index fcaae7077bcb..d2cb7206b9b3 100644 --- a/src-docs/src/views/button/button_group_icon.js +++ b/src-docs/src/views/button/button_group_icon.js @@ -45,6 +45,9 @@ export default () => { label: 'Underline', name: 'underline', iconType: 'editorUnderline', + title: 'Underline with a custom title', + titleDelay: 'short', + titlePosition: 'bottom', }, { id: `${idPrefix3}6`, diff --git a/src/components/button/button_group/button_group.styles.ts b/src/components/button/button_group/button_group.styles.ts index f044b49e193f..a818c4c7d498 100644 --- a/src/components/button/button_group/button_group.styles.ts +++ b/src/components/button/button_group/button_group.styles.ts @@ -43,7 +43,7 @@ export const euiButtonGroupButtonsStyles = (euiThemeContext: UseEuiTheme) => { fullWidth: css` ${logicalCSS('width', '100%')} - .euiButtonGroupButton { + .euiButtonGroupButton__tooltipAnchor { flex: 1; } `, diff --git a/src/components/button/button_group/button_group.tsx b/src/components/button/button_group/button_group.tsx index 066dffefc08a..e248116dadde 100644 --- a/src/components/button/button_group/button_group.tsx +++ b/src/components/button/button_group/button_group.tsx @@ -19,6 +19,7 @@ import { EuiScreenReaderOnly } from '../../accessibility'; import { CommonProps } from '../../common'; import { _EuiButtonColor } from '../../../themes/amsterdam/global_styling/mixins'; +import { EuiToolTipProps } from '../../../components/tool_tip'; import { EuiButtonDisplayContentProps } from '../button_display/_button_display_content'; import { EuiButtonGroupButton } from './button_group_button'; import { @@ -46,6 +47,18 @@ export interface EuiButtonGroupOptionProps * The type of the underlying HTML button */ type?: ButtonHTMLAttributes['type']; + /** + * Custom title content for the button, only used if isIconOnly is true + */ + title?: EuiToolTipProps['content']; + /** + * Custom title delay + */ + titleDelay?: EuiToolTipProps['delay']; + /** + * Custom title position + */ + titlePosition?: EuiToolTipProps['position']; } export type EuiButtonGroupProps = CommonProps & { @@ -177,10 +190,10 @@ export const EuiButtonGroup: FunctionComponent = ({
- {options.map((option, index) => { + {options.map((option) => { return ( { const uncompressedBorderRadii = ( radiusSize: CSSProperties['borderRadius'] ) => ` - border-radius: 0; + & > .euiButtonGroupButton { + border-radius: 0; + } - &:first-child { + &:first-child > .euiButtonGroupButton { ${logicalShorthandCSS('border-radius', `${radiusSize} 0 0 ${radiusSize}`)} } - &:last-child { + &:last-child > .euiButtonGroupButton { ${logicalShorthandCSS('border-radius', `0 ${radiusSize} ${radiusSize} 0`)} } `; return { // Base - euiButtonGroupButton: css` + euiButtonGroupButtonTooltipAnchor: css` /* Allow button to shrink and truncate */ ${logicalCSS('min-width', 0)} flex-shrink: 1; flex-grow: 0; + `, + euiButtonGroupButton: css` + ${logicalCSS('width', '100%')} + ${logicalCSS('min-width', 0)} ${euiCanAnimate} { transition: background-color ${euiTheme.animation.normal} ease-in-out, @@ -77,40 +83,46 @@ export const euiButtonGroupButtonStyles = (euiThemeContext: UseEuiTheme) => { ${uncompressedBorderRadii(euiTheme.border.radius.medium)} `, uncompressed: css` - &:is(.euiButtonGroupButton-isSelected) { + & > .euiButtonGroupButton:is(.euiButtonGroupButton-isSelected) { font-weight: ${euiTheme.font.weight.bold}; } /* "Borders" between buttons - should be present between two of the same colored buttons, and absent between selected vs non-selected buttons (different colors) */ - &:not(.euiButtonGroupButton-isSelected) - + .euiButtonGroupButton:not(.euiButtonGroupButton-isSelected) { + &:not(.euiButtonGroupButton__tooltipAnchor-isSelected) + + .euiButtonGroupButton__tooltipAnchor:not( + .euiButtonGroupButton__tooltipAnchor-isSelected + ) + > .euiButtonGroupButton { box-shadow: -${euiTheme.border.width.thin} 0 0 0 ${transparentize(euiTheme.colors.fullShade, 0.1)}; } - &:is(.euiButtonGroupButton-isSelected) - + .euiButtonGroupButton-isSelected { + &:is(.euiButtonGroupButton__tooltipAnchor-isSelected) + + .euiButtonGroupButton__tooltipAnchor-isSelected + > .euiButtonGroupButton { box-shadow: -${euiTheme.border.width.thin} 0 0 0 ${transparentize(euiTheme.colors.emptyShade, 0.2)}; } `, compressed: css` - ${logicalCSS('height', compressedButtonHeight)} - line-height: ${compressedButtonHeight}; - - /* Offset the background color from the border by clipping background to before the padding starts */ - padding: ${mathWithUnits(euiTheme.border.width.thin, (x) => x * 2)}; - background-clip: content-box; - /* Tweak border radius to account for the padding & background-clip */ - border-radius: ${mathWithUnits( - [controlCompressedBorderRadius, euiTheme.border.width.thin], - (x, y) => x + y - )}; - - font-weight: ${euiTheme.font.weight.regular}; - - &:is(.euiButtonGroupButton-isSelected) { - font-weight: ${euiTheme.font.weight.semiBold}; + & > .euiButtonGroupButton { + ${logicalCSS('height', compressedButtonHeight)} + line-height: ${compressedButtonHeight}; + + /* Offset the background color from the border by clipping background to before the padding starts */ + padding: ${mathWithUnits(euiTheme.border.width.thin, (x) => x * 2)}; + background-clip: content-box; + /* Tweak border radius to account for the padding & background-clip */ + border-radius: ${mathWithUnits( + [controlCompressedBorderRadius, euiTheme.border.width.thin], + (x, y) => x + y + )}; + + font-weight: ${euiTheme.font.weight.regular}; + + &:is(.euiButtonGroupButton-isSelected) { + font-weight: ${euiTheme.font.weight.semiBold}; + } } `, // States diff --git a/src/components/button/button_group/button_group_button.tsx b/src/components/button/button_group/button_group_button.tsx index 19d767eae92f..65d65e260396 100644 --- a/src/components/button/button_group/button_group_button.tsx +++ b/src/components/button/button_group/button_group_button.tsx @@ -7,7 +7,7 @@ */ import classNames from 'classnames'; -import React, { FunctionComponent, MouseEventHandler } from 'react'; +import React, { FunctionComponent, MouseEventHandler, useRef } from 'react'; import { useEuiTheme } from '../../../services'; import { useEuiButtonColorCSS } from '../../../themes/amsterdam/global_styling/mixins/button'; @@ -20,6 +20,7 @@ import { _compressedButtonFocusColor, _uncompressedButtonFocus, } from './button_group_button.styles'; +import { EuiToolTip } from '../../../components/tool_tip'; type Props = EuiButtonGroupOptionProps & { /** @@ -54,6 +55,10 @@ export const EuiButtonGroupButton: FunctionComponent = ({ value, // Prevent prop from being spread size, color: _color = 'primary', + title, + titleDelay = 'long', + titlePosition = 'top', + onClick, ...rest }) => { const isCompressed = size === 'compressed'; @@ -70,8 +75,6 @@ export const EuiButtonGroupButton: FunctionComponent = ({ const cssStyles = [ styles.euiButtonGroupButton, isIconOnly && styles.iconOnly, - styles[size!], - !isCompressed && styles.uncompressed, isDisabled && isSelected ? styles.disabledAndSelected : buttonColorStyles, !isDisabled && focusColorStyles, ]; @@ -100,25 +103,49 @@ export const EuiButtonGroupButton: FunctionComponent = ({ * the base width of the button via the `euiTextShift()` method in SASS. */ const [buttonTextRef, innerText] = useInnerText(); + const tooltipRef = useRef(null); + + const onClickOverride: React.MouseEventHandler = (e) => { + // Blur the tooltip so it doesn't stick around after click until rehovered/refocused + tooltipRef.current?.onBlur(); + onClick(e); + }; return ( - - {label} - + + {label} + + ); }; From d935cfb7392e96c513af2d654b9169407f58c65c Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Sat, 13 Jan 2024 20:20:56 -0400 Subject: [PATCH 02/17] Update button group snapshots --- .../__snapshots__/button_group.test.tsx.snap | 3844 +++++++++-------- 1 file changed, 2048 insertions(+), 1796 deletions(-) diff --git a/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap b/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap index 3b3e3aab7b6e..dc64e847a869 100644 --- a/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap +++ b/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap @@ -12,70 +12,79 @@ exports[`EuiButtonGroup button props buttonSize compressed is rendered for multi
- - - + + + + + + + + +
`; @@ -92,70 +101,79 @@ exports[`EuiButtonGroup button props buttonSize compressed is rendered for singl
- - - + + + + + + + + +
`; @@ -172,70 +190,79 @@ exports[`EuiButtonGroup button props buttonSize m is rendered for multi 1`] = `
- - - + + + + + + + + +
`; @@ -252,70 +279,79 @@ exports[`EuiButtonGroup button props buttonSize m is rendered for single 1`] = `
- - - + + + + + + + + +
`; @@ -332,70 +368,79 @@ exports[`EuiButtonGroup button props buttonSize s is rendered for multi 1`] = `
- - - + + + + + + + + +
`; @@ -412,70 +457,79 @@ exports[`EuiButtonGroup button props buttonSize s is rendered for single 1`] = `
- - - + + + + + + + + +
`; @@ -492,70 +546,79 @@ exports[`EuiButtonGroup button props color accent is rendered for multi 1`] = `
- - - + + + + + + + + +
`; @@ -572,70 +635,79 @@ exports[`EuiButtonGroup button props color accent is rendered for single 1`] = `
- - - + + + + + + + + +
`; @@ -652,70 +724,79 @@ exports[`EuiButtonGroup button props color danger is rendered for multi 1`] = `
- - - + + + + + + + + +
`; @@ -732,70 +813,79 @@ exports[`EuiButtonGroup button props color danger is rendered for single 1`] = `
- - - + + + + + + + + +
`; @@ -812,70 +902,79 @@ exports[`EuiButtonGroup button props color primary is rendered for multi 1`] = `
- - - + + + + + + + + +
`; @@ -892,70 +991,79 @@ exports[`EuiButtonGroup button props color primary is rendered for single 1`] =
- - - + + + + + + + + +
`; @@ -972,70 +1080,79 @@ exports[`EuiButtonGroup button props color success is rendered for multi 1`] = `
- - - + + + + + + + + +
`; @@ -1052,70 +1169,79 @@ exports[`EuiButtonGroup button props color success is rendered for single 1`] =
- - - + + + + + + + + +
`; @@ -1132,70 +1258,79 @@ exports[`EuiButtonGroup button props color text is rendered for multi 1`] = `
- - - + + + + + + + + +
`; @@ -1212,70 +1347,79 @@ exports[`EuiButtonGroup button props color text is rendered for single 1`] = `
- - - + + + + + + + + +
`; @@ -1292,70 +1436,79 @@ exports[`EuiButtonGroup button props color warning is rendered for multi 1`] = `
- - - + + + + + + + + +
`; @@ -1372,70 +1525,79 @@ exports[`EuiButtonGroup button props color warning is rendered for single 1`] =
- - - + + + + + + + + +
`; @@ -1453,72 +1615,81 @@ exports[`EuiButtonGroup button props isDisabled is rendered for multi 1`] = `
- - - + + + + + + + + +
`; @@ -1536,72 +1707,81 @@ exports[`EuiButtonGroup button props isDisabled is rendered for single 1`] = `
- - - + + + + + + + + +
`; @@ -1618,70 +1798,79 @@ exports[`EuiButtonGroup button props isFullWidth is rendered for multi 1`] = `
- - - + + + + + + + + +
`; @@ -1698,70 +1887,79 @@ exports[`EuiButtonGroup button props isFullWidth is rendered for single 1`] = `
- - - + + + + + + + + +
`; @@ -1778,70 +1976,79 @@ exports[`EuiButtonGroup button props isIconOnly is rendered for multi 1`] = `
- - - + + + + + + + + +
`; @@ -1858,70 +2065,79 @@ exports[`EuiButtonGroup button props isIconOnly is rendered for single 1`] = `
- - - + + + + + + + + +
`; @@ -1938,70 +2154,79 @@ exports[`EuiButtonGroup type="multi" idToSelectedMap 1`] = `
- - - + + + + + + + + +
`; @@ -2020,70 +2245,79 @@ exports[`EuiButtonGroup type="multi" renders 1`] = `
- - - + + + + + + + + +
`; @@ -2100,70 +2334,79 @@ exports[`EuiButtonGroup type="single" idSelected 1`] = `
- - - + + + + + + + + +
`; @@ -2182,70 +2425,79 @@ exports[`EuiButtonGroup type="single" renders 1`] = `
- - - + + + + + + + + +
`; From 2a9d44af257267a2722108a30eaa0c324a0cbb89 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Sat, 13 Jan 2024 20:47:33 -0400 Subject: [PATCH 03/17] Update unit tests and snapshots --- .../column_sorting.test.tsx.snap | 58 ++++++++++--------- .../column_sorting_draggable.test.tsx.snap | 58 ++++++++++--------- .../column_sorting_draggable.test.tsx | 20 ++++--- 3 files changed, 76 insertions(+), 60 deletions(-) diff --git a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap index cd7eee17d4da..6571fc668d8b 100644 --- a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap +++ b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap @@ -690,42 +690,48 @@ exports[`useDataGridColumnSorting columnSorting [React 18] renders a toolbar but
- - + +
diff --git a/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap index 23050b9a8fab..1da25143ab39 100644 --- a/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap +++ b/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap @@ -379,42 +379,48 @@ exports[`EuiDataGridColumnSortingDraggable [React 18] renders an EuiDraggable co
- - + +
diff --git a/src/components/datagrid/controls/column_sorting_draggable.test.tsx b/src/components/datagrid/controls/column_sorting_draggable.test.tsx index 0f275b4a79c6..2b7909451357 100644 --- a/src/components/datagrid/controls/column_sorting_draggable.test.tsx +++ b/src/components/datagrid/controls/column_sorting_draggable.test.tsx @@ -106,13 +106,15 @@ describe('EuiDataGridColumnSortingDraggable', () => { ); expect( - getByTestSubject('euiDataGridColumnSorting-sortColumn-columnA-asc') - .title + getByTestSubject( + 'euiDataGridColumnSorting-sortColumn-columnA-asc' + )?.querySelector('[data-text]')?.textContent ).toEqual('A-Z'); expect( - getByTestSubject('euiDataGridColumnSorting-sortColumn-columnA-desc') - .title + getByTestSubject( + 'euiDataGridColumnSorting-sortColumn-columnA-desc' + )?.querySelector('[data-text]')?.textContent ).toEqual('Z-A'); }); @@ -131,13 +133,15 @@ describe('EuiDataGridColumnSortingDraggable', () => { ); expect( - getByTestSubject('euiDataGridColumnSorting-sortColumn-columnA-asc') - .title + getByTestSubject( + 'euiDataGridColumnSorting-sortColumn-columnA-asc' + )?.querySelector('[data-text]')?.textContent ).toEqual('False-True'); expect( - getByTestSubject('euiDataGridColumnSorting-sortColumn-columnA-desc') - .title + getByTestSubject( + 'euiDataGridColumnSorting-sortColumn-columnA-desc' + )?.querySelector('[data-text]')?.textContent ).toEqual('True-False'); }); }); From d5d6e96a1a79b73e7886abed01a0710ca148f8b4 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Sat, 13 Jan 2024 21:45:32 -0400 Subject: [PATCH 04/17] Add unit tests for button group tooltips --- .../button/button_group/button_group.test.tsx | 208 +++++++++++++++++- 1 file changed, 207 insertions(+), 1 deletion(-) diff --git a/src/components/button/button_group/button_group.test.tsx b/src/components/button/button_group/button_group.test.tsx index d5c4a5239cec..933ea3ab23f3 100644 --- a/src/components/button/button_group/button_group.test.tsx +++ b/src/components/button/button_group/button_group.test.tsx @@ -8,7 +8,11 @@ import React from 'react'; import { css } from '@emotion/react'; -import { render } from '../../../test/rtl'; +import { + render, + waitForEuiToolTipHidden, + waitForEuiToolTipVisible, +} from '../../../test/rtl'; import { requiredProps as commonProps } from '../../../test'; import { shouldRenderCustomStyles } from '../../../test/internal'; @@ -18,6 +22,7 @@ import { EuiButtonGroupProps, } from './button_group'; import { BUTTON_COLORS } from '../../../themes/amsterdam/global_styling/mixins'; +import { act, fireEvent } from '@testing-library/react'; const SIZES: Array = [ 's', @@ -216,4 +221,205 @@ describe('EuiButtonGroup', () => { 'text-transform: uppercase' ); }); + + describe('tooltips', () => { + it('shows a tooltip on hover', async () => { + const { getByTestSubject, getByRole } = render( + + ); + fireEvent.mouseOver(getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipVisible(); + expect(getByRole('tooltip')).toHaveTextContent('Option 4'); + }); + + it('shows a tooltip on focus', async () => { + const { getByTestSubject, getByRole } = render( + + ); + fireEvent.focus(getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipVisible(); + expect(getByRole('tooltip')).toHaveTextContent('Option 4'); + }); + + it('allows overriding the default title', async () => { + const { getByTestSubject, getByRole } = render( + + ); + fireEvent.mouseOver(getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipVisible(); + expect(getByRole('tooltip')).toHaveTextContent('I am a tooltip'); + }); + + it('allows customizing the tooltip delay', async () => { + let result = render( + + ); + fireEvent.mouseOver(result.getByTestSubject('buttonWithTooltip')); + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + }); + expect(result.queryByRole('tooltip')).toBeNull(); + result.unmount(); + result = render( + + ); + fireEvent.mouseOver(result.getByTestSubject('buttonWithTooltip')); + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + }); + expect(result.queryByRole('tooltip')).not.toBeNull(); + }); + + it('allows customizing the tooltip position', async () => { + let result = render( + + ); + fireEvent.mouseOver(result.getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipVisible(); + expect(result.getByRole('tooltip')).toHaveAttribute( + 'data-position', + 'top' + ); + result.unmount(); + result = render( + + ); + fireEvent.mouseOver(result.getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipVisible(); + expect(result.getByRole('tooltip')).toHaveAttribute( + 'data-position', + 'bottom' + ); + }); + + it('does not show a tooltip for buttons with visible text', async () => { + const { getByTestSubject, queryByRole } = render( + + ); + fireEvent.mouseOver(getByTestSubject('buttonWithTooltip')); + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + }); + expect(queryByRole('tooltip')).toBeNull(); + }); + + it('hides the tooltip on click until rehovered/refocused', async () => { + const { getByTestSubject, queryByRole } = render( + + ); + fireEvent.mouseOver(getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipVisible(); + fireEvent.click(getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipHidden(); + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + }); + expect(queryByRole('tooltip')).toBeNull(); + fireEvent.focus(getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipVisible(); + fireEvent.click(getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipHidden(); + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, 500)); + }); + expect(queryByRole('tooltip')).toBeNull(); + }); + }); }); From 12f4a693d6257954e044d1cd7c54cb4468d6c231 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Sat, 13 Jan 2024 22:42:03 -0400 Subject: [PATCH 05/17] Document new prop defaults and add changelog entry --- changelogs/upcoming/7461.md | 2 ++ src/components/button/button_group/button_group.tsx | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 changelogs/upcoming/7461.md diff --git a/changelogs/upcoming/7461.md b/changelogs/upcoming/7461.md new file mode 100644 index 000000000000..6d51d6dd404a --- /dev/null +++ b/changelogs/upcoming/7461.md @@ -0,0 +1,2 @@ +- Added support for showing `EuiTooltip` components for `EuiButtonGroup` button titles + diff --git a/src/components/button/button_group/button_group.tsx b/src/components/button/button_group/button_group.tsx index e248116dadde..f7c375497b31 100644 --- a/src/components/button/button_group/button_group.tsx +++ b/src/components/button/button_group/button_group.tsx @@ -53,10 +53,12 @@ export interface EuiButtonGroupOptionProps title?: EuiToolTipProps['content']; /** * Custom title delay + * @default 'long' */ titleDelay?: EuiToolTipProps['delay']; /** * Custom title position + * @default 'top' */ titlePosition?: EuiToolTipProps['position']; } From 71a2f05b8c5e42c155ad229784ce7d1f0bea5500 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Thu, 18 Jan 2024 23:22:34 -0400 Subject: [PATCH 06/17] Update React 16 and 17 snapshots --- .../column_sorting.test.tsx.snap | 116 ++++++++++-------- .../column_sorting_draggable.test.tsx.snap | 116 ++++++++++-------- 2 files changed, 128 insertions(+), 104 deletions(-) diff --git a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap index 6571fc668d8b..dc946709b82d 100644 --- a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap +++ b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap @@ -150,42 +150,48 @@ exports[`useDataGridColumnSorting columnSorting [React 16] renders a toolbar but
- - + +
@@ -420,42 +426,48 @@ exports[`useDataGridColumnSorting columnSorting [React 17] renders a toolbar but
- - + +
diff --git a/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap index 1da25143ab39..37c5c4483967 100644 --- a/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap +++ b/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap @@ -87,42 +87,48 @@ exports[`EuiDataGridColumnSortingDraggable [React 16] renders an EuiDraggable co
- - + +
@@ -233,42 +239,48 @@ exports[`EuiDataGridColumnSortingDraggable [React 17] renders an EuiDraggable co
- - + +
From 5336e36364faed060ea7aa2bcbd89d4457a0ae32 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Sat, 24 Feb 2024 00:10:10 -0400 Subject: [PATCH 07/17] Switch from title, titleDelay, and titlePosition props to toolTipContent and toolTipProps props for tooltips, and restore default title attribute behaviour --- .../__snapshots__/button_group.test.tsx.snap | 84 +++++++++++++++++++ .../button/button_group/button_group.test.tsx | 79 +++++++++-------- .../button/button_group/button_group.tsx | 14 +--- .../button_group/button_group_button.tsx | 31 ++++--- 4 files changed, 151 insertions(+), 57 deletions(-) diff --git a/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap b/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap index dc64e847a869..defa590e67b8 100644 --- a/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap +++ b/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap @@ -20,6 +20,7 @@ exports[`EuiButtonGroup button props buttonSize compressed is rendered for multi aria-pressed="false" class="euiButtonGroupButton testClass1 testClass2 emotion-euiButtonDisplay-s-defaultMinWidth-euiButtonGroupButton-empty-text-euiTestCss" data-test-subj="test subject string" + title="Option one" type="button" > { { id: 'buttonWithTooltip', label: 'Option 4', + toolTipContent: 'I am a tooltip', }, ]} /> ); fireEvent.mouseOver(getByTestSubject('buttonWithTooltip')); await waitForEuiToolTipVisible(); - expect(getByRole('tooltip')).toHaveTextContent('Option 4'); + expect(getByRole('tooltip')).toHaveTextContent('I am a tooltip'); }); it('shows a tooltip on focus', async () => { @@ -252,17 +253,18 @@ describe('EuiButtonGroup', () => { { id: 'buttonWithTooltip', label: 'Option 4', + toolTipContent: 'I am a tooltip', }, ]} /> ); fireEvent.focus(getByTestSubject('buttonWithTooltip')); await waitForEuiToolTipVisible(); - expect(getByRole('tooltip')).toHaveTextContent('Option 4'); + expect(getByRole('tooltip')).toHaveTextContent('I am a tooltip'); }); - it('allows overriding the default title', async () => { - const { getByTestSubject, getByRole } = render( + it('should automatically add a title attribute with the provided label if no tooltip is provided', () => { + const { getByTestSubject } = render( { { id: 'buttonWithTooltip', label: 'Option 4', - title: 'I am a tooltip', }, ]} /> ); - fireEvent.mouseOver(getByTestSubject('buttonWithTooltip')); - await waitForEuiToolTipVisible(); - expect(getByRole('tooltip')).toHaveTextContent('I am a tooltip'); + expect(getByTestSubject('buttonWithTooltip')).toHaveAttribute( + 'title', + 'Option 4' + ); + }); + + it('should not add a title attribute if a tooltip is provided', () => { + const { getByTestSubject } = render( + + ); + expect(getByTestSubject('buttonWithTooltip')).not.toHaveAttribute( + 'title' + ); }); it('allows customizing the tooltip delay', async () => { @@ -291,7 +313,10 @@ describe('EuiButtonGroup', () => { { id: 'buttonWithTooltip', label: 'Option 4', - title: 'I am a tooltip', + toolTipContent: 'I am a tooltip', + toolTipProps: { + delay: 'long', + }, }, ]} /> @@ -311,8 +336,10 @@ describe('EuiButtonGroup', () => { { id: 'buttonWithTooltip', label: 'Option 4', - title: 'I am a tooltip', - titleDelay: 'regular', + toolTipContent: 'I am a tooltip', + toolTipProps: { + delay: 'regular', + }, }, ]} /> @@ -334,7 +361,7 @@ describe('EuiButtonGroup', () => { { id: 'buttonWithTooltip', label: 'Option 4', - title: 'I am a tooltip', + toolTipContent: 'I am a tooltip', }, ]} /> @@ -355,8 +382,10 @@ describe('EuiButtonGroup', () => { { id: 'buttonWithTooltip', label: 'Option 4', - title: 'I am a tooltip', - titlePosition: 'bottom', + toolTipContent: 'I am a tooltip', + toolTipProps: { + position: 'bottom', + }, }, ]} /> @@ -369,27 +398,6 @@ describe('EuiButtonGroup', () => { ); }); - it('does not show a tooltip for buttons with visible text', async () => { - const { getByTestSubject, queryByRole } = render( - - ); - fireEvent.mouseOver(getByTestSubject('buttonWithTooltip')); - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 500)); - }); - expect(queryByRole('tooltip')).toBeNull(); - }); - it('hides the tooltip on click until rehovered/refocused', async () => { const { getByTestSubject, queryByRole } = render( { { id: 'buttonWithTooltip', label: 'Option 4', + toolTipContent: 'I am a tooltip', }, ]} /> diff --git a/src/components/button/button_group/button_group.tsx b/src/components/button/button_group/button_group.tsx index f7c375497b31..e20c6677eb09 100644 --- a/src/components/button/button_group/button_group.tsx +++ b/src/components/button/button_group/button_group.tsx @@ -48,19 +48,13 @@ export interface EuiButtonGroupOptionProps */ type?: ButtonHTMLAttributes['type']; /** - * Custom title content for the button, only used if isIconOnly is true + * Custom tooltip content for the button */ - title?: EuiToolTipProps['content']; + toolTipContent?: EuiToolTipProps['content']; /** - * Custom title delay - * @default 'long' + * Custom tooltip props for the button */ - titleDelay?: EuiToolTipProps['delay']; - /** - * Custom title position - * @default 'top' - */ - titlePosition?: EuiToolTipProps['position']; + toolTipProps?: Partial>; } export type EuiButtonGroupProps = CommonProps & { diff --git a/src/components/button/button_group/button_group_button.tsx b/src/components/button/button_group/button_group_button.tsx index 65d65e260396..dd01d0bc29cd 100644 --- a/src/components/button/button_group/button_group_button.tsx +++ b/src/components/button/button_group/button_group_button.tsx @@ -55,9 +55,8 @@ export const EuiButtonGroupButton: FunctionComponent = ({ value, // Prevent prop from being spread size, color: _color = 'primary', - title, - titleDelay = 'long', - titlePosition = 'top', + toolTipContent, + toolTipProps, onClick, ...rest }) => { @@ -103,28 +102,35 @@ export const EuiButtonGroupButton: FunctionComponent = ({ * the base width of the button via the `euiTextShift()` method in SASS. */ const [buttonTextRef, innerText] = useInnerText(); - const tooltipRef = useRef(null); + const toolTipRef = useRef(null); const onClickOverride: React.MouseEventHandler = (e) => { // Blur the tooltip so it doesn't stick around after click until rehovered/refocused - tooltipRef.current?.onBlur(); + toolTipRef.current?.onBlur(); onClick(e); }; return ( @@ -139,6 +145,7 @@ export const EuiButtonGroupButton: FunctionComponent = ({ ref: buttonTextRef, 'data-text': innerText, }} + title={toolTipContent ? undefined : innerText} data-test-subj={id} isSelected={isSelected} onClick={onClickOverride} From a1a583500cfae96ae6c2249e413882c936d9701a Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Sat, 24 Feb 2024 00:22:18 -0400 Subject: [PATCH 08/17] Revert changes to column_sorting tests --- .../column_sorting.test.tsx.snap | 6 ++++++ .../column_sorting_draggable.test.tsx.snap | 6 ++++++ .../column_sorting_draggable.test.tsx | 20 ++++++++----------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap index dc946709b82d..f2bf4d044292 100644 --- a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap +++ b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap @@ -157,6 +157,7 @@ exports[`useDataGridColumnSorting columnSorting [React 16] renders a toolbar but aria-pressed="true" class="euiButtonGroupButton euiButtonGroupButton-isSelected emotion-euiButtonDisplay-s-defaultMinWidth-euiButtonGroupButton-fill-text" data-test-subj="euiDataGridColumnSorting-sortColumn-columnA-asc" + title="Low-High" type="button" > { ); expect( - getByTestSubject( - 'euiDataGridColumnSorting-sortColumn-columnA-asc' - )?.querySelector('[data-text]')?.textContent + getByTestSubject('euiDataGridColumnSorting-sortColumn-columnA-asc') + .title ).toEqual('A-Z'); expect( - getByTestSubject( - 'euiDataGridColumnSorting-sortColumn-columnA-desc' - )?.querySelector('[data-text]')?.textContent + getByTestSubject('euiDataGridColumnSorting-sortColumn-columnA-desc') + .title ).toEqual('Z-A'); }); @@ -133,15 +131,13 @@ describe('EuiDataGridColumnSortingDraggable', () => { ); expect( - getByTestSubject( - 'euiDataGridColumnSorting-sortColumn-columnA-asc' - )?.querySelector('[data-text]')?.textContent + getByTestSubject('euiDataGridColumnSorting-sortColumn-columnA-asc') + .title ).toEqual('False-True'); expect( - getByTestSubject( - 'euiDataGridColumnSorting-sortColumn-columnA-desc' - )?.querySelector('[data-text]')?.textContent + getByTestSubject('euiDataGridColumnSorting-sortColumn-columnA-desc') + .title ).toEqual('True-False'); }); }); From fabad0cc3da0b24728e8171f950989fde3359906 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Sat, 24 Feb 2024 00:23:48 -0400 Subject: [PATCH 09/17] Update changelog entry --- changelogs/upcoming/7461.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/upcoming/7461.md b/changelogs/upcoming/7461.md index 6d51d6dd404a..97c718cd26cc 100644 --- a/changelogs/upcoming/7461.md +++ b/changelogs/upcoming/7461.md @@ -1,2 +1,2 @@ -- Added support for showing `EuiTooltip` components for `EuiButtonGroup` button titles +- Added support for showing `EuiTooltip` components on `EuiButtonGroup` buttons From 2a3872d47a65a55c06de238d73e6e306d2daf12f Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Sat, 24 Feb 2024 01:10:49 -0400 Subject: [PATCH 10/17] Add button group tooltip examples --- src-docs/src/views/button/button_example.js | 53 +++++++++++++++++++ .../src/views/button/button_group_icon.js | 3 -- .../src/views/button/button_group_tooltips.js | 42 +++++++++++++++ 3 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 src-docs/src/views/button/button_group_tooltips.js diff --git a/src-docs/src/views/button/button_example.js b/src-docs/src/views/button/button_example.js index 196852c5ecc7..0b2e80d1920c 100644 --- a/src-docs/src/views/button/button_example.js +++ b/src-docs/src/views/button/button_example.js @@ -236,6 +236,28 @@ const buttonGroupCompressedSnippet = [ />`, ]; +import ButtonGroupToolTips from './button_group_tooltips'; +const buttonGroupToolTipsSource = require('!!raw-loader!./button_group_tooltips'); +const buttonGroupToolTipsSnippet = [ + ` {}} +/>`, +]; + export const ButtonExample = { title: 'Button', intro: ( @@ -697,6 +719,37 @@ export const ButtonExample = { props: { EuiButtonGroup, EuiButtonGroupOptionProps }, demoPanelProps: { color: 'subdued' }, }, + { + source: [ + { + type: GuideSectionTypes.JS, + code: buttonGroupToolTipsSource, + }, + ], + + text: ( + <> +

Button group tooltips

+

+ Buttons within a button group will automatically get a{' '} + title attribute containing the button{' '} + label, which displays a default browser tooltip. +

+

+ To instead display an EuiToolTip containing + custom content, you can add a toolTipContent prop + to the button options. +

+

+ You can also use toolTipProps to customize + tooltip placement, title, and other behaviors. +

+ + ), + demo: , + snippet: buttonGroupToolTipsSnippet, + props: { EuiButtonGroup, EuiButtonGroupOptionProps }, + }, ], guidelines: , }; diff --git a/src-docs/src/views/button/button_group_icon.js b/src-docs/src/views/button/button_group_icon.js index d2cb7206b9b3..fcaae7077bcb 100644 --- a/src-docs/src/views/button/button_group_icon.js +++ b/src-docs/src/views/button/button_group_icon.js @@ -45,9 +45,6 @@ export default () => { label: 'Underline', name: 'underline', iconType: 'editorUnderline', - title: 'Underline with a custom title', - titleDelay: 'short', - titlePosition: 'bottom', }, { id: `${idPrefix3}6`, diff --git a/src-docs/src/views/button/button_group_tooltips.js b/src-docs/src/views/button/button_group_tooltips.js new file mode 100644 index 000000000000..9318caa2bb09 --- /dev/null +++ b/src-docs/src/views/button/button_group_tooltips.js @@ -0,0 +1,42 @@ +import React, { useState } from 'react'; + +import { EuiButtonGroup } from '../../../../src/components'; + +export default () => { + const toggleButtons = [ + { + id: 'buttonGroup__0', + label: 'Default title', + }, + { + id: 'buttonGroup__1', + label: 'Custom tooltip content', + toolTipContent: 'This is a custom tooltip', + }, + { + id: 'buttonGroup__2', + label: 'Custom tooltip props', + toolTipContent: 'This is another custom tooltip', + toolTipProps: { + title: 'My custom title', + delay: 'regular', + position: 'right', + }, + }, + ]; + + const [toggleIdSelected, setToggleIdSelected] = useState('buttonGroup__1'); + + const onChange = (optionId) => { + setToggleIdSelected(optionId); + }; + + return ( + onChange(id)} + /> + ); +}; From 5be0af31b6d9814eaad4d721961d7bba6235757f Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 8 Mar 2024 21:56:11 -0800 Subject: [PATCH 11/17] Misc cleanup - props docs copy - simplify tests, import order --- .../button/button_group/button_group.test.tsx | 127 ++++-------------- .../button/button_group/button_group.tsx | 4 +- 2 files changed, 27 insertions(+), 104 deletions(-) diff --git a/src/components/button/button_group/button_group.test.tsx b/src/components/button/button_group/button_group.test.tsx index eccf6b2fbc0a..74446be8aeca 100644 --- a/src/components/button/button_group/button_group.test.tsx +++ b/src/components/button/button_group/button_group.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { css } from '@emotion/react'; +import { act, fireEvent } from '@testing-library/react'; import { render, waitForEuiToolTipHidden, @@ -16,13 +17,12 @@ import { import { requiredProps as commonProps } from '../../../test'; import { shouldRenderCustomStyles } from '../../../test/internal'; +import { BUTTON_COLORS } from '../../../themes/amsterdam/global_styling/mixins'; import { EuiButtonGroup, EuiButtonGroupOptionProps, EuiButtonGroupProps, } from './button_group'; -import { BUTTON_COLORS } from '../../../themes/amsterdam/global_styling/mixins'; -import { act, fireEvent } from '@testing-library/react'; const SIZES: Array = [ 's', @@ -223,7 +223,7 @@ describe('EuiButtonGroup', () => { }); describe('tooltips', () => { - it('shows a tooltip on hover', async () => { + it('shows a tooltip on hover and focus', async () => { const { getByTestSubject, getByRole } = render( { ); fireEvent.mouseOver(getByTestSubject('buttonWithTooltip')); await waitForEuiToolTipVisible(); + expect(getByRole('tooltip')).toHaveTextContent('I am a tooltip'); + + fireEvent.mouseOut(getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipHidden(); + + fireEvent.focus(getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipVisible(); + fireEvent.blur(getByTestSubject('buttonWithTooltip')); + await waitForEuiToolTipHidden(); }); - it('shows a tooltip on focus', async () => { - const { getByTestSubject, getByRole } = render( + it('allows customizing the tooltip via `toolTipProps`', async () => { + const { getByTestSubject } = render( { id: 'buttonWithTooltip', label: 'Option 4', toolTipContent: 'I am a tooltip', + toolTipProps: { + position: 'right', + delay: 'regular', + 'data-test-subj': 'toolTipTest', + }, }, ]} /> ); - fireEvent.focus(getByTestSubject('buttonWithTooltip')); + fireEvent.mouseOver(getByTestSubject('buttonWithTooltip')); await waitForEuiToolTipVisible(); - expect(getByRole('tooltip')).toHaveTextContent('I am a tooltip'); + + expect(getByTestSubject('toolTipTest')).toHaveAttribute( + 'data-position', + 'right' + ); }); it('should automatically add a title attribute with the provided label if no tooltip is provided', () => { @@ -303,101 +321,6 @@ describe('EuiButtonGroup', () => { ); }); - it('allows customizing the tooltip delay', async () => { - let result = render( - - ); - fireEvent.mouseOver(result.getByTestSubject('buttonWithTooltip')); - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 500)); - }); - expect(result.queryByRole('tooltip')).toBeNull(); - result.unmount(); - result = render( - - ); - fireEvent.mouseOver(result.getByTestSubject('buttonWithTooltip')); - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 500)); - }); - expect(result.queryByRole('tooltip')).not.toBeNull(); - }); - - it('allows customizing the tooltip position', async () => { - let result = render( - - ); - fireEvent.mouseOver(result.getByTestSubject('buttonWithTooltip')); - await waitForEuiToolTipVisible(); - expect(result.getByRole('tooltip')).toHaveAttribute( - 'data-position', - 'top' - ); - result.unmount(); - result = render( - - ); - fireEvent.mouseOver(result.getByTestSubject('buttonWithTooltip')); - await waitForEuiToolTipVisible(); - expect(result.getByRole('tooltip')).toHaveAttribute( - 'data-position', - 'bottom' - ); - }); - it('hides the tooltip on click until rehovered/refocused', async () => { const { getByTestSubject, queryByRole } = render( ['type']; /** - * Custom tooltip content for the button + * Optional custom tooltip content for the button */ toolTipContent?: EuiToolTipProps['content']; /** - * Custom tooltip props for the button + * Optional props to pass to the underlying **[EuiToolTip](/#/display/tooltip)** */ toolTipProps?: Partial>; } From 3b3761d6bf60c0dc1ab888294ca9687d242d99d9 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 8 Mar 2024 21:44:39 -0800 Subject: [PATCH 12/17] Clean up rendered DOM & CSS approach - make tooltip conditional so it only renders the extra anchor wrapper if `toolTipContent` exists - tweak conditional styles conditionally to target button vs tooltip anchor as needed - DRY out uncompressed border logic --- .../__snapshots__/button_group.test.tsx.snap | 3928 ++++++++--------- .../button_group/button_group.stories.tsx | 35 +- .../button_group/button_group.styles.ts | 4 +- .../button_group_button.styles.ts | 118 +- .../button_group/button_group_button.tsx | 75 +- .../column_sorting.test.tsx.snap | 180 +- .../column_sorting_draggable.test.tsx.snap | 180 +- 7 files changed, 2101 insertions(+), 2419 deletions(-) diff --git a/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap b/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap index defa590e67b8..3b3e3aab7b6e 100644 --- a/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap +++ b/src/components/button/button_group/__snapshots__/button_group.test.tsx.snap @@ -12,82 +12,70 @@ exports[`EuiButtonGroup button props buttonSize compressed is rendered for multi
- - - - - - - - - + + +
`; @@ -104,82 +92,70 @@ exports[`EuiButtonGroup button props buttonSize compressed is rendered for singl
- - - - - - - - - + + +
`; @@ -196,82 +172,70 @@ exports[`EuiButtonGroup button props buttonSize m is rendered for multi 1`] = `
- - - - - - - - - + + +
`; @@ -288,82 +252,70 @@ exports[`EuiButtonGroup button props buttonSize m is rendered for single 1`] = `
- - - - - - - - - + + +
`; @@ -380,82 +332,70 @@ exports[`EuiButtonGroup button props buttonSize s is rendered for multi 1`] = `
- - - - - - - - - + + +
`; @@ -472,82 +412,70 @@ exports[`EuiButtonGroup button props buttonSize s is rendered for single 1`] = `
- - - - - - - - - + + +
`; @@ -564,82 +492,70 @@ exports[`EuiButtonGroup button props color accent is rendered for multi 1`] = `
- - - - - - - - - + + +
`; @@ -656,82 +572,70 @@ exports[`EuiButtonGroup button props color accent is rendered for single 1`] = `
- - - - - - - - - + + +
`; @@ -748,82 +652,70 @@ exports[`EuiButtonGroup button props color danger is rendered for multi 1`] = `
- - - - - - - - - + + +
`; @@ -840,82 +732,70 @@ exports[`EuiButtonGroup button props color danger is rendered for single 1`] = `
- - - - - - - - - + + +
`; @@ -932,82 +812,70 @@ exports[`EuiButtonGroup button props color primary is rendered for multi 1`] = `
- - - - - - - - - + + +
`; @@ -1024,82 +892,70 @@ exports[`EuiButtonGroup button props color primary is rendered for single 1`] =
- - - - - - - - - + + +
`; @@ -1116,82 +972,70 @@ exports[`EuiButtonGroup button props color success is rendered for multi 1`] = `
- - - - - - - - - + + +
`; @@ -1208,82 +1052,70 @@ exports[`EuiButtonGroup button props color success is rendered for single 1`] =
- - - - - - - - - + + +
`; @@ -1300,82 +1132,70 @@ exports[`EuiButtonGroup button props color text is rendered for multi 1`] = `
- - - - - - - - - + + +
`; @@ -1392,82 +1212,70 @@ exports[`EuiButtonGroup button props color text is rendered for single 1`] = `
- - - - - - - - - + + +
`; @@ -1484,82 +1292,70 @@ exports[`EuiButtonGroup button props color warning is rendered for multi 1`] = `
- - - - - - - - - + + +
`; @@ -1576,82 +1372,70 @@ exports[`EuiButtonGroup button props color warning is rendered for single 1`] =
- - - - - - - - - + + +
`; @@ -1669,84 +1453,72 @@ exports[`EuiButtonGroup button props isDisabled is rendered for multi 1`] = `
- - - - - - - - - + + +
`; @@ -1764,84 +1536,72 @@ exports[`EuiButtonGroup button props isDisabled is rendered for single 1`] = `
- - - - - - - - - + + +
`; @@ -1858,82 +1618,70 @@ exports[`EuiButtonGroup button props isFullWidth is rendered for multi 1`] = `
- - - - - - - - - + + +
`; @@ -1950,82 +1698,70 @@ exports[`EuiButtonGroup button props isFullWidth is rendered for single 1`] = `
- - - - - - - - - + + +
`; @@ -2042,82 +1778,70 @@ exports[`EuiButtonGroup button props isIconOnly is rendered for multi 1`] = `
- - - - - - - - - + + +
`; @@ -2134,82 +1858,70 @@ exports[`EuiButtonGroup button props isIconOnly is rendered for single 1`] = `
- - - - - - - - - + + +
`; @@ -2226,82 +1938,70 @@ exports[`EuiButtonGroup type="multi" idToSelectedMap 1`] = `
- - - - - - - - - + + +
`; @@ -2320,82 +2020,70 @@ exports[`EuiButtonGroup type="multi" renders 1`] = `
- - - - - - - - - + + +
`; @@ -2412,82 +2100,70 @@ exports[`EuiButtonGroup type="single" idSelected 1`] = `
- - - - - - - - - + + +
`; @@ -2506,82 +2182,70 @@ exports[`EuiButtonGroup type="single" renders 1`] = `
- - - - - - - - - + + +
`; diff --git a/src/components/button/button_group/button_group.stories.tsx b/src/components/button/button_group/button_group.stories.tsx index d4f0eef2928f..ecf1ad121d6f 100644 --- a/src/components/button/button_group/button_group.stories.tsx +++ b/src/components/button/button_group/button_group.stories.tsx @@ -36,9 +36,6 @@ const meta: Meta = { options: { control: 'array', }, - buttonSize: { - control: 'select', - }, }, args: { // Component defaults @@ -109,7 +106,6 @@ const EuiButtonGroupMulti = (props: any) => { @@ -126,3 +122,34 @@ export const MultiSelection: Story = { }, argTypes: disableStorybookControls(['type']), }; + +export const WithToolTips: Story = { + render: ({ ...args }) => , + args: { + legend: 'EuiButtonGroup - tooltip UI testing', + options: [ + { + id: 'button1', + label: 'No tooltip', + }, + { + id: 'button2', + label: 'Standard tooltip', + toolTipContent: 'Hello world', + }, + { + id: 'button3', + label: 'Custom tooltip', + toolTipContent: 'Short delay and custom tooltip position', + toolTipProps: { + position: 'right', + delay: 'regular', + title: 'Hello world', + }, + }, + ], + type: 'multi', + idToSelectedMap: { button1: true }, + }, + argTypes: disableStorybookControls(['type']), +}; diff --git a/src/components/button/button_group/button_group.styles.ts b/src/components/button/button_group/button_group.styles.ts index 0b6ddd6e325f..cd934fc9d26b 100644 --- a/src/components/button/button_group/button_group.styles.ts +++ b/src/components/button/button_group/button_group.styles.ts @@ -41,8 +41,10 @@ export const euiButtonGroupButtonsStyles = (euiThemeContext: UseEuiTheme) => { fullWidth: css` ${logicalCSS('width', '100%')} - .euiButtonGroupButton__tooltipAnchor { + .euiButtonGroupButton, + .euiButtonGroup__tooltipWrapper { flex: 1; + ${logicalCSS('width', '100%')} } `, // Sizes diff --git a/src/components/button/button_group/button_group_button.styles.ts b/src/components/button/button_group/button_group_button.styles.ts index fc6f699dabef..7cbc6760bebc 100644 --- a/src/components/button/button_group/button_group_button.styles.ts +++ b/src/components/button/button_group/button_group_button.styles.ts @@ -42,30 +42,24 @@ export const euiButtonGroupButtonStyles = (euiThemeContext: UseEuiTheme) => { const uncompressedBorderRadii = ( radiusSize: CSSProperties['borderRadius'] ) => ` - & > .euiButtonGroupButton { - border-radius: 0; - } + border-radius: 0; - &:first-child > .euiButtonGroupButton { + &:first-child { ${logicalShorthandCSS('border-radius', `${radiusSize} 0 0 ${radiusSize}`)} } - &:last-child > .euiButtonGroupButton { + &:last-child { ${logicalShorthandCSS('border-radius', `0 ${radiusSize} ${radiusSize} 0`)} } `; return { // Base - euiButtonGroupButtonTooltipAnchor: css` + euiButtonGroupButton: css` /* Allow button to shrink and truncate */ ${logicalCSS('min-width', 0)} flex-shrink: 1; flex-grow: 0; - `, - euiButtonGroupButton: css` - ${logicalCSS('width', '100%')} - ${logicalCSS('min-width', 0)} ${euiCanAnimate} { transition: background-color ${euiTheme.animation.normal} ease-in-out, @@ -76,53 +70,64 @@ export const euiButtonGroupButtonStyles = (euiThemeContext: UseEuiTheme) => { padding-inline: ${euiTheme.size.s}; `, // Sizes - s: css` - ${uncompressedBorderRadii(euiTheme.border.radius.small)} - `, - m: css` - ${uncompressedBorderRadii(euiTheme.border.radius.medium)} - `, - uncompressed: css` - & > .euiButtonGroupButton:is(.euiButtonGroupButton-isSelected) { - font-weight: ${euiTheme.font.weight.bold}; - } - - /* "Borders" between buttons - should be present between two of the same colored buttons, - and absent between selected vs non-selected buttons (different colors) */ - - &:not(.euiButtonGroupButton__tooltipAnchor-isSelected) - + .euiButtonGroupButton__tooltipAnchor:not( - .euiButtonGroupButton__tooltipAnchor-isSelected - ) - > .euiButtonGroupButton { - box-shadow: -${euiTheme.border.width.thin} 0 0 0 ${transparentize(euiTheme.colors.fullShade, 0.1)}; - } - - &:is(.euiButtonGroupButton__tooltipAnchor-isSelected) - + .euiButtonGroupButton__tooltipAnchor-isSelected - > .euiButtonGroupButton { - box-shadow: -${euiTheme.border.width.thin} 0 0 0 ${transparentize(euiTheme.colors.emptyShade, 0.2)}; - } - `, + uncompressed: { + uncompressed: css` + &:is(.euiButtonGroupButton-isSelected) { + font-weight: ${euiTheme.font.weight.bold}; + } + `, + get borders() { + const selectors = + '.euiButtonGroupButton-isSelected, .euiButtonGroup__tooltipWrapper-isSelected'; + const selectedColor = transparentize(euiTheme.colors.emptyShade, 0.2); + const unselectedColor = transparentize(euiTheme.colors.fullShade, 0.1); + const borderWidth = euiTheme.border.width.thin; + + // "Borders" between buttons should be present between two of the same colored buttons, + // and absent between selected vs non-selected buttons (different colors) + return ` + &:not(${selectors}) + *:not(${selectors}) { + box-shadow: -${borderWidth} 0 0 0 ${unselectedColor}; + } + &:is(${selectors}) + *:is(${selectors}) { + box-shadow: -${borderWidth} 0 0 0 ${selectedColor}; + } + `; + }, + get s() { + return css` + ${this.borders} + ${uncompressedBorderRadii(euiTheme.border.radius.small)} + `; + }, + get m() { + return css` + ${this.borders} + ${uncompressedBorderRadii(euiTheme.border.radius.medium)} + `; + }, + hasToolTip: css` + /* Set the border-radius on the tooltip anchor element instead and inherit from that */ + border-radius: inherit; + `, + }, compressed: css` - & > .euiButtonGroupButton { - ${logicalCSS('height', compressedButtonHeight)} - line-height: ${compressedButtonHeight}; - - /* Offset the background color from the border by clipping background to before the padding starts */ - padding: ${mathWithUnits(euiTheme.border.width.thin, (x) => x * 2)}; - background-clip: content-box; - /* Tweak border radius to account for the padding & background-clip */ - border-radius: ${mathWithUnits( - [controlCompressedBorderRadius, euiTheme.border.width.thin], - (x, y) => x + y - )}; + ${logicalCSS('height', compressedButtonHeight)} + line-height: ${compressedButtonHeight}; + + /* Offset the background color from the border by clipping background to before the padding starts */ + padding: ${mathWithUnits(euiTheme.border.width.thin, (x) => x * 2)}; + background-clip: content-box; + /* Tweak border radius to account for the padding & background-clip */ + border-radius: ${mathWithUnits( + [controlCompressedBorderRadius, euiTheme.border.width.thin], + (x, y) => x + y + )}; - font-weight: ${euiTheme.font.weight.regular}; + font-weight: ${euiTheme.font.weight.regular}; - &:is(.euiButtonGroupButton-isSelected) { - font-weight: ${euiTheme.font.weight.semiBold}; - } + &:is(.euiButtonGroupButton-isSelected) { + font-weight: ${euiTheme.font.weight.semiBold}; } `, // States @@ -132,6 +137,11 @@ export const euiButtonGroupButtonStyles = (euiThemeContext: UseEuiTheme) => { )}; background-color: ${euiTheme.colors.disabled}; `, + // Tooltip anchor wrapper + tooltipWrapper: css` + /* Without this on the tooltip anchor, button text truncation doesn't work */ + overflow: hidden; + `, // Content wrapper content: { euiButtonGroupButton__content: css``, diff --git a/src/components/button/button_group/button_group_button.tsx b/src/components/button/button_group/button_group_button.tsx index dd01d0bc29cd..c3a4dcb5334a 100644 --- a/src/components/button/button_group/button_group_button.tsx +++ b/src/components/button/button_group/button_group_button.tsx @@ -7,7 +7,13 @@ */ import classNames from 'classnames'; -import React, { FunctionComponent, MouseEventHandler, useRef } from 'react'; +import React, { + FunctionComponent, + MouseEventHandler, + ReactElement, + useRef, +} from 'react'; +import { CSSInterpolation } from '@emotion/css'; import { useEuiTheme } from '../../../services'; import { useEuiButtonColorCSS } from '../../../themes/amsterdam/global_styling/mixins/button'; @@ -34,7 +40,7 @@ type Props = EuiButtonGroupOptionProps & { /** * Inherit from EuiButtonGroup */ - size: EuiButtonGroupProps['buttonSize']; + size: NonNullable; /** * Inherit from EuiButtonGroup */ @@ -63,6 +69,7 @@ export const EuiButtonGroupButton: FunctionComponent = ({ const isCompressed = size === 'compressed'; const color = isDisabled ? 'disabled' : _color; const display = isSelected ? 'fill' : isCompressed ? 'empty' : 'base'; + const hasToolTip = !!toolTipContent; const euiTheme = useEuiTheme(); const buttonColorStyles = useEuiButtonColorCSS({ display })[color]; @@ -74,9 +81,16 @@ export const EuiButtonGroupButton: FunctionComponent = ({ const cssStyles = [ styles.euiButtonGroupButton, isIconOnly && styles.iconOnly, + !isCompressed && + (hasToolTip ? styles.uncompressed.hasToolTip : styles.uncompressed[size]), + isCompressed ? styles.compressed : styles.uncompressed.uncompressed, isDisabled && isSelected ? styles.disabledAndSelected : buttonColorStyles, !isDisabled && focusColorStyles, ]; + const tooltipWrapperStyles = [ + styles.tooltipWrapper, + !isCompressed && styles.uncompressed[size], + ]; const contentStyles = [ styles.content.euiButtonGroupButton__content, isCompressed && styles.content.compressed, @@ -111,28 +125,11 @@ export const EuiButtonGroupButton: FunctionComponent = ({ }; return ( - = ({ > {label} + + ); +}; + +const EuiButtonGroupButtonWithToolTip: FunctionComponent< + Pick & { + children: ReactElement; + wrapperCss: CSSInterpolation; + isSelected: boolean; + } +> = ({ toolTipContent, toolTipProps, wrapperCss, isSelected, children }) => { + return toolTipContent ? ( + + {children} + ) : ( + children ); }; diff --git a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap index f2bf4d044292..cd7eee17d4da 100644 --- a/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap +++ b/src/components/datagrid/controls/__snapshots__/column_sorting.test.tsx.snap @@ -150,50 +150,42 @@ exports[`useDataGridColumnSorting columnSorting [React 16] renders a toolbar but
- - - - + + - + +
@@ -428,50 +420,42 @@ exports[`useDataGridColumnSorting columnSorting [React 17] renders a toolbar but
- - - - + + - + +
@@ -706,50 +690,42 @@ exports[`useDataGridColumnSorting columnSorting [React 18] renders a toolbar but
- - - - + + - + +
diff --git a/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap b/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap index a654e7326756..23050b9a8fab 100644 --- a/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap +++ b/src/components/datagrid/controls/__snapshots__/column_sorting_draggable.test.tsx.snap @@ -87,50 +87,42 @@ exports[`EuiDataGridColumnSortingDraggable [React 16] renders an EuiDraggable co
- - - - + + - + +
@@ -241,50 +233,42 @@ exports[`EuiDataGridColumnSortingDraggable [React 17] renders an EuiDraggable co
- - - - + + - + +
@@ -395,50 +379,42 @@ exports[`EuiDataGridColumnSortingDraggable [React 18] renders an EuiDraggable co
- - - - + + - + +
From d2e41ea8dc8e7b8769fe316c34dc48c08380398e Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 8 Mar 2024 21:59:09 -0800 Subject: [PATCH 13/17] Revert opinionated default `title` unset on buttons with tooltips - but allow consumers to opt in on disabling the `title` if they want to, depending on their copy and use case --- .../button/button_group/button_group.test.tsx | 32 ++++++------------- .../button/button_group/button_group.tsx | 6 ++++ .../button_group/button_group_button.tsx | 2 +- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/components/button/button_group/button_group.test.tsx b/src/components/button/button_group/button_group.test.tsx index 74446be8aeca..548d95d45794 100644 --- a/src/components/button/button_group/button_group.test.tsx +++ b/src/components/button/button_group/button_group.test.tsx @@ -281,27 +281,10 @@ describe('EuiButtonGroup', () => { ); }); - it('should automatically add a title attribute with the provided label if no tooltip is provided', () => { - const { getByTestSubject } = render( - - ); - expect(getByTestSubject('buttonWithTooltip')).toHaveAttribute( - 'title', - 'Option 4' - ); - }); + it('allows consumers to unset the `title` in favor of a tooltip', () => { + const reallyLongLabel = + 'This is a really long label that we know will be truncated, so we show a tooltip instead and hide the title'; - it('should not add a title attribute if a tooltip is provided', () => { const { getByTestSubject } = render( { ...options, { id: 'buttonWithTooltip', - label: 'Option 4', - toolTipContent: 'I am a tooltip', + label: reallyLongLabel, + toolTipContent: reallyLongLabel, + title: undefined, }, ]} /> @@ -319,6 +303,10 @@ describe('EuiButtonGroup', () => { expect(getByTestSubject('buttonWithTooltip')).not.toHaveAttribute( 'title' ); + expect(getByTestSubject('button01')).toHaveAttribute( + 'title', + 'Option two' + ); }); it('hides the tooltip on click until rehovered/refocused', async () => { diff --git a/src/components/button/button_group/button_group.tsx b/src/components/button/button_group/button_group.tsx index ec298c9a44db..c3055990ac28 100644 --- a/src/components/button/button_group/button_group.tsx +++ b/src/components/button/button_group/button_group.tsx @@ -47,6 +47,12 @@ export interface EuiButtonGroupOptionProps * The type of the underlying HTML button */ type?: ButtonHTMLAttributes['type']; + /** + * By default, will use the button text for the native browser title. + * + * This can be either customized or unset via `title: ''` if necessary. + */ + title?: ButtonHTMLAttributes['title']; /** * Optional custom tooltip content for the button */ diff --git a/src/components/button/button_group/button_group_button.tsx b/src/components/button/button_group/button_group_button.tsx index c3a4dcb5334a..b38c53f2ca9d 100644 --- a/src/components/button/button_group/button_group_button.tsx +++ b/src/components/button/button_group/button_group_button.tsx @@ -142,7 +142,7 @@ export const EuiButtonGroupButton: FunctionComponent = ({ ref: buttonTextRef, 'data-text': innerText, }} - title={toolTipContent ? undefined : innerText} + title={innerText} data-test-subj={id} isSelected={isSelected} onClick={onClickOverride} From 00d204ab900e1cb872f978b331116a56876d47a2 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 8 Mar 2024 22:56:01 -0800 Subject: [PATCH 14/17] Remove inaccessible/opinionated blur on click - this is not an accessible default and EUI should not be baking this in. I've provided an example of how consumers could override this via their own state if they absolutely had to, although it's still not my favorite and has UX friction if users click super quickly, etc --- .../button_group/button_group.stories.tsx | 48 ++++++++++++++++--- .../button/button_group/button_group.test.tsx | 35 +------------- .../button_group/button_group_button.tsx | 10 ---- 3 files changed, 43 insertions(+), 50 deletions(-) diff --git a/src/components/button/button_group/button_group.stories.tsx b/src/components/button/button_group/button_group.stories.tsx index ecf1ad121d6f..b96d0ecfdcb9 100644 --- a/src/components/button/button_group/button_group.stories.tsx +++ b/src/components/button/button_group/button_group.stories.tsx @@ -6,10 +6,11 @@ * Side Public License, v 1. */ -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { disableStorybookControls } from '../../../../.storybook/utils'; +import { useEuiTheme } from '../../../services'; import { EuiButtonGroup, EuiButtonGroupProps, @@ -123,29 +124,64 @@ export const MultiSelection: Story = { argTypes: disableStorybookControls(['type']), }; -export const WithToolTips: Story = { - render: ({ ...args }) => , +export const WithTooltips: Story = { + render: function Render({ options, ...args }: EuiButtonGroupProps) { + const { euiTheme } = useEuiTheme(); + const [toolTipHidden, forceToolTipHidden] = useState(false); + const forceHiddenToolTip = useCallback(() => forceToolTipHidden(true), []); + const resetVisibility = useCallback(() => forceToolTipHidden(false), []); + + if (options[2].toolTipProps) { + options[2].toolTipProps = { + ...options[2].toolTipProps, + // Example of how a consumer could force hiding the tooltip + // via `toolTipProps`, state, and custom CSS + anchorProps: { + onClick: forceHiddenToolTip, + onBlurCapture: resetVisibility, + onMouseEnter: resetVisibility, + onMouseLeave: forceHiddenToolTip, + }, + css: [ + { + transition: `opacity ${euiTheme.animation.normal} ${euiTheme.animation.resistance}`, + animationFillMode: 'none !important', + }, + toolTipHidden + ? { opacity: '0 !important', pointerEvents: 'none' } + : { opacity: '1' }, + ], + }; + } + + return ; + }, args: { legend: 'EuiButtonGroup - tooltip UI testing', + isIconOnly: true, // Start example with icons to demonstrate usefulness of tooltips options: [ { id: 'button1', + iconType: 'securitySignal', label: 'No tooltip', }, { id: 'button2', + iconType: 'securitySignalResolved', label: 'Standard tooltip', toolTipContent: 'Hello world', }, { - id: 'button3', + id: 'customToolTipProps', + iconType: 'securitySignalDetected', label: 'Custom tooltip', - toolTipContent: 'Short delay and custom tooltip position', + toolTipContent: 'Custom tooltip position and click behavior', toolTipProps: { position: 'right', - delay: 'regular', title: 'Hello world', }, + // Consumers could also opt to hide titles if preferred + title: '', }, ], type: 'multi', diff --git a/src/components/button/button_group/button_group.test.tsx b/src/components/button/button_group/button_group.test.tsx index 548d95d45794..28b549607d9c 100644 --- a/src/components/button/button_group/button_group.test.tsx +++ b/src/components/button/button_group/button_group.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { css } from '@emotion/react'; -import { act, fireEvent } from '@testing-library/react'; +import { fireEvent } from '@testing-library/react'; import { render, waitForEuiToolTipHidden, @@ -308,38 +308,5 @@ describe('EuiButtonGroup', () => { 'Option two' ); }); - - it('hides the tooltip on click until rehovered/refocused', async () => { - const { getByTestSubject, queryByRole } = render( - - ); - fireEvent.mouseOver(getByTestSubject('buttonWithTooltip')); - await waitForEuiToolTipVisible(); - fireEvent.click(getByTestSubject('buttonWithTooltip')); - await waitForEuiToolTipHidden(); - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 500)); - }); - expect(queryByRole('tooltip')).toBeNull(); - fireEvent.focus(getByTestSubject('buttonWithTooltip')); - await waitForEuiToolTipVisible(); - fireEvent.click(getByTestSubject('buttonWithTooltip')); - await waitForEuiToolTipHidden(); - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 500)); - }); - expect(queryByRole('tooltip')).toBeNull(); - }); }); }); diff --git a/src/components/button/button_group/button_group_button.tsx b/src/components/button/button_group/button_group_button.tsx index b38c53f2ca9d..f9a51bfb16a4 100644 --- a/src/components/button/button_group/button_group_button.tsx +++ b/src/components/button/button_group/button_group_button.tsx @@ -11,7 +11,6 @@ import React, { FunctionComponent, MouseEventHandler, ReactElement, - useRef, } from 'react'; import { CSSInterpolation } from '@emotion/css'; @@ -63,7 +62,6 @@ export const EuiButtonGroupButton: FunctionComponent = ({ color: _color = 'primary', toolTipContent, toolTipProps, - onClick, ...rest }) => { const isCompressed = size === 'compressed'; @@ -116,13 +114,6 @@ export const EuiButtonGroupButton: FunctionComponent = ({ * the base width of the button via the `euiTextShift()` method in SASS. */ const [buttonTextRef, innerText] = useInnerText(); - const toolTipRef = useRef(null); - - const onClickOverride: React.MouseEventHandler = (e) => { - // Blur the tooltip so it doesn't stick around after click until rehovered/refocused - toolTipRef.current?.onBlur(); - onClick(e); - }; return ( = ({ title={innerText} data-test-subj={id} isSelected={isSelected} - onClick={onClickOverride} {...rest} > {label} From d1c076a332f6013ef96215cbc19c05411218d962 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 8 Mar 2024 23:48:05 -0800 Subject: [PATCH 15/17] More copy tweaks + add missing ids to button group subsections for easier linking --- changelogs/upcoming/7461.md | 3 +- src-docs/src/views/button/button_example.js | 32 ++++++++++----------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/changelogs/upcoming/7461.md b/changelogs/upcoming/7461.md index 97c718cd26cc..826fa6edcbb5 100644 --- a/changelogs/upcoming/7461.md +++ b/changelogs/upcoming/7461.md @@ -1,2 +1 @@ -- Added support for showing `EuiTooltip` components on `EuiButtonGroup` buttons - +- Added the following properties to `EuiButtonGroup`'s `options` configs: `toolTipContent`, `toolTipProps`, and `title`. These new properties allow wrapping buttons in `EuiToolTips`, and additionally customizing or disabling the native browser `title` tooltip. diff --git a/src-docs/src/views/button/button_example.js b/src-docs/src/views/button/button_example.js index 0b2e80d1920c..ae68720535ba 100644 --- a/src-docs/src/views/button/button_example.js +++ b/src-docs/src/views/button/button_example.js @@ -675,7 +675,7 @@ export const ButtonExample = { ], text: ( <> -

Icon only button groups

+

Icon only button groups

If you're just displaying a group of icons, add the prop{' '} isIconOnly. @@ -694,10 +694,9 @@ export const ButtonExample = { code: buttonGroupCompressedSource, }, ], - text: ( <> -

Button groups in forms

+

Button groups in forms

When using button groups within compressed forms, match the form elements by adding {'buttonSize="compressed"'}. @@ -726,29 +725,30 @@ export const ButtonExample = { code: buttonGroupToolTipsSource, }, ], - text: ( <> -

Button group tooltips

-

- Buttons within a button group will automatically get a{' '} - title attribute containing the button{' '} - label, which displays a default browser tooltip. -

+

Button group tooltips

- To instead display an EuiToolTip containing - custom content, you can add a toolTipContent prop - to the button options. + Buttons within a button group will automatically display a default + browser tooltip containing the button label text. + This can be customized or unset via the title{' '} + property in your options button configuration.

- You can also use toolTipProps to customize - tooltip placement, title, and other behaviors. + To instead display an EuiToolTip around your + button(s), pass the toolTipContent property. You + can also use toolTipProps to customize tooltip + placement, title, and any other prop that{' '} + + EuiToolTip + {' '} + accepts.

), demo: , snippet: buttonGroupToolTipsSnippet, - props: { EuiButtonGroup, EuiButtonGroupOptionProps }, + props: { EuiButtonGroupOptionProps }, }, ], guidelines: , From 85983311f3caebf29a1ea265c6f53eb754138fce Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Tue, 12 Mar 2024 18:58:41 -0700 Subject: [PATCH 16/17] Revert custom tooltip click UX storybook example --- .../button_group/button_group.stories.tsx | 38 ++----------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/src/components/button/button_group/button_group.stories.tsx b/src/components/button/button_group/button_group.stories.tsx index b96d0ecfdcb9..8e3e9a4d8d09 100644 --- a/src/components/button/button_group/button_group.stories.tsx +++ b/src/components/button/button_group/button_group.stories.tsx @@ -6,11 +6,10 @@ * Side Public License, v 1. */ -import React, { useState, useCallback } from 'react'; +import React, { useState } from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import { disableStorybookControls } from '../../../../.storybook/utils'; -import { useEuiTheme } from '../../../services'; import { EuiButtonGroup, EuiButtonGroupProps, @@ -125,37 +124,7 @@ export const MultiSelection: Story = { }; export const WithTooltips: Story = { - render: function Render({ options, ...args }: EuiButtonGroupProps) { - const { euiTheme } = useEuiTheme(); - const [toolTipHidden, forceToolTipHidden] = useState(false); - const forceHiddenToolTip = useCallback(() => forceToolTipHidden(true), []); - const resetVisibility = useCallback(() => forceToolTipHidden(false), []); - - if (options[2].toolTipProps) { - options[2].toolTipProps = { - ...options[2].toolTipProps, - // Example of how a consumer could force hiding the tooltip - // via `toolTipProps`, state, and custom CSS - anchorProps: { - onClick: forceHiddenToolTip, - onBlurCapture: resetVisibility, - onMouseEnter: resetVisibility, - onMouseLeave: forceHiddenToolTip, - }, - css: [ - { - transition: `opacity ${euiTheme.animation.normal} ${euiTheme.animation.resistance}`, - animationFillMode: 'none !important', - }, - toolTipHidden - ? { opacity: '0 !important', pointerEvents: 'none' } - : { opacity: '1' }, - ], - }; - } - - return ; - }, + render: ({ ...args }) => , args: { legend: 'EuiButtonGroup - tooltip UI testing', isIconOnly: true, // Start example with icons to demonstrate usefulness of tooltips @@ -175,9 +144,10 @@ export const WithTooltips: Story = { id: 'customToolTipProps', iconType: 'securitySignalDetected', label: 'Custom tooltip', - toolTipContent: 'Custom tooltip position and click behavior', + toolTipContent: 'Custom tooltip position and delay', toolTipProps: { position: 'right', + delay: 'regular', title: 'Hello world', }, // Consumers could also opt to hide titles if preferred From 24ee14bf75650b0146a414a28627f32938fe352e Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Thu, 14 Mar 2024 11:35:40 -0700 Subject: [PATCH 17/17] [design feedback] Regular tooltip delay --- src-docs/src/views/button/button_group_tooltips.js | 1 - src/components/button/button_group/button_group.stories.tsx | 2 +- src/components/button/button_group/button_group_button.tsx | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src-docs/src/views/button/button_group_tooltips.js b/src-docs/src/views/button/button_group_tooltips.js index 9318caa2bb09..b0fbcc48c23c 100644 --- a/src-docs/src/views/button/button_group_tooltips.js +++ b/src-docs/src/views/button/button_group_tooltips.js @@ -19,7 +19,6 @@ export default () => { toolTipContent: 'This is another custom tooltip', toolTipProps: { title: 'My custom title', - delay: 'regular', position: 'right', }, }, diff --git a/src/components/button/button_group/button_group.stories.tsx b/src/components/button/button_group/button_group.stories.tsx index 8e3e9a4d8d09..b2733522ab1c 100644 --- a/src/components/button/button_group/button_group.stories.tsx +++ b/src/components/button/button_group/button_group.stories.tsx @@ -147,7 +147,7 @@ export const WithTooltips: Story = { toolTipContent: 'Custom tooltip position and delay', toolTipProps: { position: 'right', - delay: 'regular', + delay: 'long', title: 'Hello world', }, // Consumers could also opt to hide titles if preferred diff --git a/src/components/button/button_group/button_group_button.tsx b/src/components/button/button_group/button_group_button.tsx index f9a51bfb16a4..7df986a830d7 100644 --- a/src/components/button/button_group/button_group_button.tsx +++ b/src/components/button/button_group/button_group_button.tsx @@ -154,7 +154,6 @@ const EuiButtonGroupButtonWithToolTip: FunctionComponent< return toolTipContent ? (