From 2e1d5d5005130f2d5da44abd79434b4560e794bf Mon Sep 17 00:00:00 2001 From: Kelsey Myers <52179263+kelsey-myers@users.noreply.github.com> Date: Mon, 16 Jun 2025 20:26:04 +0000 Subject: [PATCH 1/3] add notice announcements to SelectPanel --- .changeset/smooth-ideas-smile.md | 5 +++++ .../react/src/SelectPanel/SelectPanel.tsx | 22 +++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 .changeset/smooth-ideas-smile.md diff --git a/.changeset/smooth-ideas-smile.md b/.changeset/smooth-ideas-smile.md new file mode 100644 index 00000000000..b4a42989ee0 --- /dev/null +++ b/.changeset/smooth-ideas-smile.md @@ -0,0 +1,5 @@ +--- +'@primer/react': minor +--- + +Adds notice announcements to SelectPanel diff --git a/packages/react/src/SelectPanel/SelectPanel.tsx b/packages/react/src/SelectPanel/SelectPanel.tsx index 1bfef78d8a6..f5aba37f93f 100644 --- a/packages/react/src/SelectPanel/SelectPanel.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.tsx @@ -20,7 +20,7 @@ import useSafeTimeout from '../hooks/useSafeTimeout' import type {FilteredActionListLoadingType} from '../FilteredActionList/FilteredActionListLoaders' import {FilteredActionListLoadingTypes} from '../FilteredActionList/FilteredActionListLoaders' import {useFeatureFlag} from '../FeatureFlags' -import {announce} from '@primer/live-region-element' +import {announce, announceFromElement} from '@primer/live-region-element' import classes from './SelectPanel.module.css' import {clsx} from 'clsx' import {heightMap} from '../Overlay/Overlay' @@ -203,6 +203,7 @@ function Panel({ const [prevOpen, setPrevOpen] = useState(open) const initialHeightRef = useRef(0) const initialScaleRef = useRef(1) + const noticeRef = useRef(null) const [isKeyboardVisible, setIsKeyboardVisible] = useState(false) const [availablePanelHeight, setAvailablePanelHeight] = useState(undefined) const KEYBOARD_VISIBILITY_THRESHOLD = 10 @@ -424,6 +425,23 @@ function Panel({ } }, [open, isNarrowScreenSize]) + useEffect(() => { + const announceNotice = async () => { + if (!noticeRef.current) return + const liveRegion = document.querySelector('live-region') + + liveRegion?.clear() + + await announceFromElement(noticeRef.current, { + from: liveRegion ? liveRegion : undefined, + }) + } + + if (open && notice) { + announceNotice() + } + }, [notice, open]) + const anchorRef = useProvidedRefOrCreate(externalAnchorRef) const onOpen: AnchoredOverlayProps['onOpen'] = useCallback( (gesture: Parameters>[0]) => onOpenChange(true, gesture), @@ -738,7 +756,7 @@ function Panel({ ) : null} {notice && ( -
+
{iconForNoticeVariant[notice.variant]}
{notice.text}
From 7be939df73daf5985d4364036ce9884f067c171d Mon Sep 17 00:00:00 2001 From: Kelsey Myers <52179263+kelsey-myers@users.noreply.github.com> Date: Mon, 16 Jun 2025 20:41:32 +0000 Subject: [PATCH 2/3] add test --- .changeset/smooth-ideas-smile.md | 2 +- .../src/SelectPanel/SelectPanel.test.tsx | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/.changeset/smooth-ideas-smile.md b/.changeset/smooth-ideas-smile.md index b4a42989ee0..f90a1a98ff5 100644 --- a/.changeset/smooth-ideas-smile.md +++ b/.changeset/smooth-ideas-smile.md @@ -1,5 +1,5 @@ --- -'@primer/react': minor +'@primer/react': patch --- Adds notice announcements to SelectPanel diff --git a/packages/react/src/SelectPanel/SelectPanel.test.tsx b/packages/react/src/SelectPanel/SelectPanel.test.tsx index 3d105dee11a..99b66c1e9ea 100644 --- a/packages/react/src/SelectPanel/SelectPanel.test.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.test.tsx @@ -656,6 +656,56 @@ for (const useModernActionList of [false, true]) { jest.useRealTimers() }) + it('should announce notice text', async () => { + jest.useFakeTimers() + const user = userEvent.setup({ + advanceTimers: jest.advanceTimersByTime, + }) + + function SelectPanelWithNotice() { + const [selected, setSelected] = React.useState([]) + const [filter, setFilter] = React.useState('') + const [open, setOpen] = React.useState(false) + + const onSelectedChange = (selected: SelectPanelProps['items']) => { + setSelected(selected) + } + + return ( + + { + setFilter(value) + }} + open={open} + onOpenChange={isOpen => { + setOpen(isOpen) + }} + notice={{ + text: 'This is a notice', + variant: 'warning', + }} + /> + + ) + } + + renderWithFlag(, useModernActionList) + + await user.click(screen.getByText('Select items')) + expect(screen.getByLabelText('Filter items')).toHaveFocus() + + expect(getLiveRegion().getMessage('polite')?.trim()).toContain('This is a notice') + }) + it('should announce filtered results', async () => { jest.useFakeTimers() const user = userEvent.setup({ From bcaaf37f1d90158ba10d85c4050d29b4ae25d023 Mon Sep 17 00:00:00 2001 From: Kelsey Myers <52179263+kelsey-myers@users.noreply.github.com> Date: Tue, 17 Jun 2025 13:42:23 +0000 Subject: [PATCH 3/3] remove redundant tag --- packages/react/src/SelectPanel/SelectPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/SelectPanel/SelectPanel.tsx b/packages/react/src/SelectPanel/SelectPanel.tsx index bfb5f5ba0e0..f98809ca2e8 100644 --- a/packages/react/src/SelectPanel/SelectPanel.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.tsx @@ -757,7 +757,7 @@ function Panel({ ) : null}
{notice && ( -
+
{iconForNoticeVariant[notice.variant]}
{notice.text}