diff --git a/.changeset/chatty-paws-attend.md b/.changeset/chatty-paws-attend.md new file mode 100644 index 00000000000..2deee72b523 --- /dev/null +++ b/.changeset/chatty-paws-attend.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +Add keyboard-accessible tooltip for truncated ActionList.Description diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-colorblind-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-colorblind-linux.png index 3b65aab7a75..7739709b62d 100644 Binary files a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-colorblind-linux.png and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-dimmed-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-dimmed-linux.png index e0b9f8ca1c9..d1cdb05a0f8 100644 Binary files a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-dimmed-linux.png and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-high-contrast-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-high-contrast-linux.png index 19eb6178332..e3bcd407877 100644 Binary files a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-high-contrast-linux.png and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-linux.png index 3b65aab7a75..7739709b62d 100644 Binary files a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-linux.png and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-tritanopia-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-tritanopia-linux.png index 3b65aab7a75..7739709b62d 100644 Binary files a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-tritanopia-linux.png and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-colorblind-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-colorblind-linux.png index db22305f64d..35ce7b59ebc 100644 Binary files a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-colorblind-linux.png and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-high-contrast-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-high-contrast-linux.png index c671e889423..8e8d6f1811e 100644 Binary files a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-high-contrast-linux.png and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-linux.png index db22305f64d..35ce7b59ebc 100644 Binary files a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-linux.png and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-tritanopia-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-tritanopia-linux.png index db22305f64d..35ce7b59ebc 100644 Binary files a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-tritanopia-linux.png and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Text-Wrap-And-Truncation-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-colorblind-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-colorblind-linux.png new file mode 100644 index 00000000000..81097b67cb2 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-dimmed-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-dimmed-linux.png new file mode 100644 index 00000000000..e7d30b203da Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-high-contrast-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-high-contrast-linux.png new file mode 100644 index 00000000000..d4e814fca01 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-linux.png new file mode 100644 index 00000000000..81097b67cb2 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-tritanopia-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-tritanopia-linux.png new file mode 100644 index 00000000000..81097b67cb2 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-colorblind-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-colorblind-linux.png new file mode 100644 index 00000000000..80be7a8452d Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-high-contrast-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-high-contrast-linux.png new file mode 100644 index 00000000000..09ace2e6718 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-linux.png new file mode 100644 index 00000000000..80be7a8452d Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-tritanopia-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-tritanopia-linux.png new file mode 100644 index 00000000000..80be7a8452d Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Complex-Tooltip-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-colorblind-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-colorblind-linux.png new file mode 100644 index 00000000000..83159f68a84 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-dimmed-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-dimmed-linux.png new file mode 100644 index 00000000000..5e4eab06d15 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-high-contrast-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-high-contrast-linux.png new file mode 100644 index 00000000000..d12089625be Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-linux.png new file mode 100644 index 00000000000..83159f68a84 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-tritanopia-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-tritanopia-linux.png new file mode 100644 index 00000000000..83159f68a84 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-colorblind-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-colorblind-linux.png new file mode 100644 index 00000000000..eaaaaa78c39 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-high-contrast-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-high-contrast-linux.png new file mode 100644 index 00000000000..3469397fead Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-linux.png new file mode 100644 index 00000000000..eaaaaa78c39 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-linux.png differ diff --git a/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-tritanopia-linux.png b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-tritanopia-linux.png new file mode 100644 index 00000000000..eaaaaa78c39 Binary files /dev/null and b/.playwright/snapshots/components/ActionList.test.ts-snapshots/ActionList-Truncated-Inline-Tooltip-light-tritanopia-linux.png differ diff --git a/e2e/components/ActionList.test.ts b/e2e/components/ActionList.test.ts index 33522ffbda8..310ee81d2e8 100644 --- a/e2e/components/ActionList.test.ts +++ b/e2e/components/ActionList.test.ts @@ -140,6 +140,10 @@ const stories = [ title: 'All combinations', id: 'components-actionlist-examples--all-combinations', }, + { + title: 'Text Wrap And Truncation', + id: 'components-actionlist-features--text-wrap-and-truncation', + }, ] as const test.describe('ActionList', () => { @@ -160,4 +164,41 @@ test.describe('ActionList', () => { } }) } + + test.describe('Truncated Description Tooltip', () => { + for (const theme of themes) { + test(`inline truncated tooltip on focus @vrt ${theme}`, async ({page}) => { + await visit(page, { + id: 'components-actionlist-features--text-wrap-and-truncation', + globals: { + colorScheme: theme, + }, + }) + + // Focus the item with a simple truncated inline description + const inlineItem = page.getByRole('button', {name: /Inline Description/}).first() + await inlineItem.focus() + + // Tooltip uses popover attribute; wait for it to become visible + await expect(page.locator('[popover]:popover-open')).toBeVisible() + await expect(page).toHaveScreenshot(`ActionList.Truncated Inline Tooltip.${theme}.png`) + }) + + test(`complex truncated tooltip on focus @vrt ${theme}`, async ({page}) => { + await visit(page, { + id: 'components-actionlist-features--text-wrap-and-truncation', + globals: { + colorScheme: theme, + }, + }) + + // Focus the item with truncated description containing complex children (bold/italic) + const complexItem = page.getByRole('button', {name: /Description with truncation and complex children/}) + await complexItem.focus() + + await expect(page.locator('[popover]:popover-open')).toBeVisible() + await expect(page).toHaveScreenshot(`ActionList.Truncated Complex Tooltip.${theme}.png`) + }) + } + }) }) diff --git a/packages/react/src/ActionList/ActionList.module.css b/packages/react/src/ActionList/ActionList.module.css index b59c8b9ea5d..29b81e1a630 100644 --- a/packages/react/src/ActionList/ActionList.module.css +++ b/packages/react/src/ActionList/ActionList.module.css @@ -541,12 +541,12 @@ transform: scaleY(1); } - & + .SubGroup { + & ~ .SubGroup { display: none; } /* show active indicator on parent collapse if child is active */ - &:has(+ .SubGroup [data-active='true']) { + &:has(~ .SubGroup [data-active='true']) { background: var(--control-transparent-bgColor-selected); & .ItemLabel { diff --git a/packages/react/src/ActionList/ActionList.test.tsx b/packages/react/src/ActionList/ActionList.test.tsx index c7d58780488..6def3de94f5 100644 --- a/packages/react/src/ActionList/ActionList.test.tsx +++ b/packages/react/src/ActionList/ActionList.test.tsx @@ -145,7 +145,7 @@ describe('ActionList', () => { expect(container.querySelector('li[aria-disabled="true"]')?.nextElementSibling).toHaveAttribute('tabindex', '0') }) - it('sets title correctly for Description component', () => { + it('sets Description title for button-semantics items (tooltip path)', () => { const {container} = HTMLRender( @@ -168,6 +168,36 @@ describe('ActionList', () => { const descriptions = container.querySelectorAll('[data-component="ActionList.Description"]') + // For button-semantic items, the native title is suppressed in favor of + // a keyboard-accessible Tooltip rendered by the parent Item. + expect(descriptions[0]).toHaveAttribute('title', '') + expect(descriptions[1]).toHaveAttribute('title', '') + expect(descriptions[2]).not.toHaveAttribute('title') + }) + + it('sets Description title for list-semantics items (no truncation tooltip path)', () => { + const {container} = HTMLRender( + + + Option 1Simple string description + + + Option 2 + + Complex content + + + + Option 3 + + Non-truncated content + + + , + ) + + const descriptions = container.querySelectorAll('[data-component="ActionList.Description"]') + expect(descriptions[0]).toHaveAttribute('title', 'Simple string description') expect(descriptions[1]).toHaveAttribute('title', 'Complex content') expect(descriptions[2]).not.toHaveAttribute('title') diff --git a/packages/react/src/ActionList/Description.test.tsx b/packages/react/src/ActionList/Description.test.tsx index a0aabe3bcd5..5312364912e 100644 --- a/packages/react/src/ActionList/Description.test.tsx +++ b/packages/react/src/ActionList/Description.test.tsx @@ -32,7 +32,9 @@ describe('ActionList.Description', () => { const description = getByText('Item 1 description') expect(description.tagName).toBe('DIV') - expect(description).toHaveAttribute('title', 'Item 1 description') + // For button-semantic items, the native title is suppressed in favor of + // a keyboard-accessible Tooltip rendered by the parent Item. + expect(description).toHaveAttribute('title', '') expect(description).toHaveStyle('flex-basis: auto') expect(description).toHaveStyle('text-overflow: ellipsis') expect(description).toHaveStyle('overflow: hidden') diff --git a/packages/react/src/ActionList/Description.tsx b/packages/react/src/ActionList/Description.tsx index dc21f933387..07b0e4c3d5a 100644 --- a/packages/react/src/ActionList/Description.tsx +++ b/packages/react/src/ActionList/Description.tsx @@ -29,17 +29,27 @@ export const Description: FCWithSlotMarker { - const {blockDescriptionId, inlineDescriptionId} = React.useContext(ItemContext) + const {blockDescriptionId, inlineDescriptionId, setTruncatedText} = React.useContext(ItemContext) const containerRef = React.useRef(null) const [computedTitle, setComputedTitle] = React.useState('') // Extract text content from rendered DOM for tooltip React.useEffect(() => { if (truncate && containerRef.current) { - const textContent = containerRef.current.textContent || '' + const el = containerRef.current + const textContent = el.textContent || '' setComputedTitle(textContent) + if (setTruncatedText) { + setTruncatedText( + el.scrollWidth > el.clientWidth + ? typeof props.children === 'string' + ? props.children + : textContent + : undefined, + ) + } } - }, [truncate, props.children]) + }, [truncate, props.children, setTruncatedText]) const effectiveTitle = typeof props.children === 'string' ? props.children : computedTitle @@ -61,7 +71,7 @@ export const Description: FCWithSlotMarker { expect(tabs[0].nodeType).toBe(Node.ELEMENT_NODE) expect(tabs).toHaveLength(3) }) + + it('should preserve consumer ref when tooltip wraps trigger', async () => { + const user = userEvent.setup() + + function TestComponent() { + const anchorRef = React.useRef(null) + const [open, setOpen] = React.useState(false) + return ( + <> + + { + setOpen(!open) + }} + > + Convert to issue + + This description gets truncated because it is inline with truncation + + + + setOpen(false)}> + + Choose repository + Create issue + + + + ) + } + + const {getByText, queryByRole} = HTMLRender() + + // Overlay should not be visible initially + expect(queryByRole('menu')).not.toBeInTheDocument() + + // Click the item to open the anchored overlay + await user.click(getByText('Convert to issue')) + + // The overlay should open — this fails if Tooltip overwrites the consumer ref + await waitFor(() => { + expect(queryByRole('menu')).toBeInTheDocument() + }) + }) }) diff --git a/packages/react/src/ActionList/Item.tsx b/packages/react/src/ActionList/Item.tsx index f9be0d11bc7..97fbe722e2b 100644 --- a/packages/react/src/ActionList/Item.tsx +++ b/packages/react/src/ActionList/Item.tsx @@ -1,5 +1,4 @@ import React, {type JSX} from 'react' - import {useId} from '../hooks/useId' import {useSlots} from '../hooks/useSlots' import {ActionListContainerContext} from './ActionListContainerContext' @@ -16,11 +15,35 @@ import VisuallyHidden from '../_VisuallyHidden' import classes from './ActionList.module.css' import {clsx} from 'clsx' import {fixedForwardRef} from '../utils/modern-polymorphic' +import {Tooltip} from '../TooltipV2' +import {TooltipContext} from '../TooltipV2/Tooltip' type ActionListSubItemProps = { children?: React.ReactNode } +/** + * Wraps button-semantic items with Tooltip, disabled when not truncated + * For non-button-semantic items, renders children directly. + */ +const ConditionalTooltip = React.forwardRef< + HTMLElement, + { + text: string | undefined + enabled: boolean + children: React.ReactElement + } +>(function ConditionalTooltip({text, enabled, children}, forwardedRef) { + if (!enabled || !text) { + return children + } + return ( + + {children} + + ) +}) + export const SubItem: React.FC = ({children}) => { return <>{children} } @@ -185,6 +208,8 @@ const UnwrappedItem = ( const trailingVisualId = `${itemId}--trailing-visual` const inactiveWarningId = inactive && !showInactiveIndicator ? `${itemId}--warning-message` : undefined + const [truncatedText, setTruncatedText] = React.useState(undefined) + const DefaultItemWrapper = listSemantics ? DivItemContainerNoBox : ButtonItemContainerNoBox const ItemWrapper = _PrivateItemWrapper || DefaultItemWrapper @@ -209,12 +234,11 @@ const UnwrappedItem = ( 'data-inactive': inactive ? true : undefined, 'data-loading': loading && !inactive ? true : undefined, tabIndex: focusable ? undefined : 0, - 'aria-labelledby': `${labelId} ${slots.trailingVisual ? trailingVisualId : ''} ${ - slots.description && descriptionVariant === 'inline' ? inlineDescriptionId : '' - }`, + 'aria-labelledby': `${labelId} ${slots.trailingVisual ? trailingVisualId : ''}`, 'aria-describedby': [ slots.description && descriptionVariant === 'block' ? blockDescriptionId : undefined, + slots.description && descriptionVariant === 'inline' ? inlineDescriptionId : undefined, inactiveWarningId ?? undefined, ] .filter(String) @@ -248,6 +272,7 @@ const UnwrappedItem = ( inlineDescriptionId, blockDescriptionId, trailingVisualId, + setTruncatedText: buttonSemantics ? setTruncatedText : undefined, }} >
  • ( data-has-description={slots.description ? true : false} className={clsx(classes.ActionListItem, className)} > - - - - + - {slots.leadingVisual} - - - - - {childrenWithoutSlots} - {/* Loading message needs to be in here so it is read with the label */} - {/* If the item is inactive, we do not simultaneously announce that it is loading */} - {loading === true && !inactive && Loading} + {/* Reset TooltipContext so that child components don't detect + the ConditionalTooltip and suppress their own internal tooltips. */} + + + + + {slots.leadingVisual} + + + + + {childrenWithoutSlots} + {/* Loading message needs to be in here so it is read with the label */} + {/* If the item is inactive, we do not simultaneously announce that it is loading */} + {loading === true && !inactive && Loading} + + {slots.description} + + + {trailingVisual} + + + { + // If the item is inactive, but it's not in an overlay (e.g. ActionMenu, SelectPanel), + // render the inactive warning message directly in the item. + !showInactiveIndicator && inactiveText ? ( + + {inactiveText} + + ) : null + } - {slots.description} - - - {trailingVisual} - - - { - // If the item is inactive, but it's not in an overlay (e.g. ActionMenu, SelectPanel), - // render the inactive warning message directly in the item. - !showInactiveIndicator && inactiveText ? ( - - {inactiveText} - - ) : null - } - - + + + {!inactive && !loading && !menuContext && Boolean(slots.trailingAction) && slots.trailingAction} {slots.subItem}
  • diff --git a/packages/react/src/ActionList/shared.ts b/packages/react/src/ActionList/shared.ts index f652cf1b19c..af98c9cd30a 100644 --- a/packages/react/src/ActionList/shared.ts +++ b/packages/react/src/ActionList/shared.ts @@ -85,6 +85,7 @@ export type ItemContext = Pick, 'variant' blockDescriptionId?: string trailingVisualId?: string inactive?: boolean + setTruncatedText?: (text: string | undefined) => void } export const ItemContext = React.createContext({}) diff --git a/packages/react/src/TooltipV2/Tooltip.tsx b/packages/react/src/TooltipV2/Tooltip.tsx index 92f0599da98..bd33f49c562 100644 --- a/packages/react/src/TooltipV2/Tooltip.tsx +++ b/packages/react/src/TooltipV2/Tooltip.tsx @@ -360,10 +360,10 @@ export const Tooltip: ForwardRefExoticComponent< {text} {/* There is a bug in Chrome browsers where `aria-hidden` text inside the target of an `aria-labelledby` - still gets included in the accessible label. `KeybindingHint` renders the symbols as `aria-hidden` text - and renders full key names as `VisuallyHidden` text. Due to the browser bug this causes the label text - to duplicate the symbols and key names. To work around this, we exclude the hint from being part of the - label and instead render the plain keybinding description string. */} + still gets included in the accessible label. `KeybindingHint` renders the symbols as `aria-hidden` text + and renders full key names as `VisuallyHidden` text. Due to the browser bug this causes the label text + to duplicate the symbols and key names. To work around this, we exclude the hint from being part of the + label and instead render the plain keybinding description string. */} ({getAccessibleKeybindingHintString(keybindingHint, isMacOS)})