From 293339e70801dd0088ac9062c04fbb5506940a93 Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Thu, 5 Oct 2023 09:11:40 +0200 Subject: [PATCH 1/3] fix: A11y fixes * The entire MessageBar has role `group` * The entire MessageBar is labelled by the MessageBarTitle * Added guidance about restoring focus --- .../etc/react-message-bar-preview.api.md | 5 ++--- .../src/components/MessageBar/MessageBar.types.ts | 6 ++---- .../src/components/MessageBar/useMessageBar.ts | 6 +++++- .../src/components/MessageBar/useMessageBarContextValues.ts | 5 +++-- .../src/components/MessageBarTitle/useMessageBarTitle.ts | 4 ++++ .../src/contexts/messageBarContext.ts | 2 ++ 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/react-components/react-message-bar-preview/etc/react-message-bar-preview.api.md b/packages/react-components/react-message-bar-preview/etc/react-message-bar-preview.api.md index cb6bc178a490bd..cbcd2b363e9084 100644 --- a/packages/react-components/react-message-bar-preview/etc/react-message-bar-preview.api.md +++ b/packages/react-components/react-message-bar-preview/etc/react-message-bar-preview.api.md @@ -63,6 +63,7 @@ export type MessageBarContextValue = { layout: 'multiline' | 'singleline' | 'auto'; actionsRef: React_2.MutableRefObject; bodyRef: React_2.MutableRefObject; + titleId: string; }; // @public @@ -105,10 +106,8 @@ export type MessageBarSlots = { }; // @public -export type MessageBarState = ComponentState & Required> & { +export type MessageBarState = ComponentState & Required> & Pick & { transitionClassName: string; - actionsRef: React_2.MutableRefObject; - bodyRef: React_2.MutableRefObject; }; // @public diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBar/MessageBar.types.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBar/MessageBar.types.ts index 3488ba0456ae17..f2ad4afaf42311 100644 --- a/packages/react-components/react-message-bar-preview/src/components/MessageBar/MessageBar.types.ts +++ b/packages/react-components/react-message-bar-preview/src/components/MessageBar/MessageBar.types.ts @@ -1,6 +1,5 @@ import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; import type { MessageBarContextValue } from '../../contexts/messageBarContext'; -import * as React from 'react'; export type MessageBarSlots = { root: Slot<'div'>; @@ -32,8 +31,7 @@ export type MessageBarProps = ComponentProps & * State used in rendering MessageBar */ export type MessageBarState = ComponentState & - Required> & { + Required> & + Pick & { transitionClassName: string; - actionsRef: React.MutableRefObject; - bodyRef: React.MutableRefObject; }; diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBar.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBar.ts index bfb8df9816fad0..07e6dadd56f668 100644 --- a/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBar.ts +++ b/packages/react-components/react-message-bar-preview/src/components/MessageBar/useMessageBar.ts @@ -1,5 +1,5 @@ import * as React from 'react'; -import { getIntrinsicElementProps, slot, useMergedRefs } from '@fluentui/react-utilities'; +import { getIntrinsicElementProps, slot, useId, useMergedRefs } from '@fluentui/react-utilities'; import { useAnnounce_unstable } from '@fluentui/react-shared-contexts'; import type { MessageBarProps, MessageBarState } from './MessageBar.types'; import { getIntentIcon } from './getIntentIcon'; @@ -25,6 +25,7 @@ export const useMessageBar_unstable = (props: MessageBarProps, ref: React.Ref(null); const bodyRef = React.useRef(null); const { announce } = useAnnounce_unstable(); + const titleId = useId(); React.useEffect(() => { const bodyMessage = bodyRef.current?.textContent; @@ -42,6 +43,8 @@ export const useMessageBar_unstable = (props: MessageBarProps, ref: React.Ref ({ layout, actionsRef, bodyRef, + titleId, }), - [layout, actionsRef, bodyRef], + [layout, actionsRef, bodyRef, titleId], ); return { diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/useMessageBarTitle.ts b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/useMessageBarTitle.ts index 9861811bb1fce9..d464ea18cd7719 100644 --- a/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/useMessageBarTitle.ts +++ b/packages/react-components/react-message-bar-preview/src/components/MessageBarTitle/useMessageBarTitle.ts @@ -1,6 +1,7 @@ import * as React from 'react'; import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities'; import type { MessageBarTitleProps, MessageBarTitleState } from './MessageBarTitle.types'; +import { useMessageBarContext } from '../../contexts/messageBarContext'; /** * Create the state required to render MessageBarTitle. @@ -15,6 +16,8 @@ export const useMessageBarTitle_unstable = ( props: MessageBarTitleProps, ref: React.Ref, ): MessageBarTitleState => { + const { titleId } = useMessageBarContext(); + return { components: { root: 'span', @@ -22,6 +25,7 @@ export const useMessageBarTitle_unstable = ( root: slot.always( getIntrinsicElementProps('span', { ref, + id: titleId, ...props, }), { elementType: 'span' }, diff --git a/packages/react-components/react-message-bar-preview/src/contexts/messageBarContext.ts b/packages/react-components/react-message-bar-preview/src/contexts/messageBarContext.ts index f2bb40b5a84905..a44509f2c73ed9 100644 --- a/packages/react-components/react-message-bar-preview/src/contexts/messageBarContext.ts +++ b/packages/react-components/react-message-bar-preview/src/contexts/messageBarContext.ts @@ -4,10 +4,12 @@ export type MessageBarContextValue = { layout: 'multiline' | 'singleline' | 'auto'; actionsRef: React.MutableRefObject; bodyRef: React.MutableRefObject; + titleId: string; }; const messageBarContext = React.createContext(undefined); export const messageBarContextDefaultValue: MessageBarContextValue = { + titleId: '', layout: 'singleline', actionsRef: React.createRef(), bodyRef: React.createRef(), From 15978c76a8bab808aecfe332be8b030d14739aa1 Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Thu, 5 Oct 2023 09:40:39 +0200 Subject: [PATCH 2/3] changefile --- ...e-bar-preview-499e36e9-6912-4a07-92dc-fadbf8feebef.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@fluentui-react-message-bar-preview-499e36e9-6912-4a07-92dc-fadbf8feebef.json diff --git a/change/@fluentui-react-message-bar-preview-499e36e9-6912-4a07-92dc-fadbf8feebef.json b/change/@fluentui-react-message-bar-preview-499e36e9-6912-4a07-92dc-fadbf8feebef.json new file mode 100644 index 00000000000000..a3bc09d542afa0 --- /dev/null +++ b/change/@fluentui-react-message-bar-preview-499e36e9-6912-4a07-92dc-fadbf8feebef.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: screenreader narration improvements", + "packageName": "@fluentui/react-message-bar-preview", + "email": "lingfangao@hotmail.com", + "dependentChangeType": "patch" +} From d2b596a478317eba1ea19d8f9feeafb7b0f3b8de Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Thu, 5 Oct 2023 10:11:02 +0200 Subject: [PATCH 3/3] tests --- .../src/components/MessageBar/MessageBar.test.tsx | 5 +++++ .../MessageBar/__snapshots__/MessageBar.test.tsx.snap | 2 ++ .../__snapshots__/MessageBarTitle.test.tsx.snap | 1 + 3 files changed, 8 insertions(+) diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBar/MessageBar.test.tsx b/packages/react-components/react-message-bar-preview/src/components/MessageBar/MessageBar.test.tsx index 54012eec2b44dc..8b01f7a5cffb6b 100644 --- a/packages/react-components/react-message-bar-preview/src/components/MessageBar/MessageBar.test.tsx +++ b/packages/react-components/react-message-bar-preview/src/components/MessageBar/MessageBar.test.tsx @@ -6,6 +6,7 @@ import { AnnounceProvider_unstable } from '@fluentui/react-shared-contexts'; import { MessageBarBody } from '../MessageBarBody/MessageBarBody'; import { MessageBarTitle } from '../MessageBarTitle/MessageBarTitle'; import { MessageBarActions } from '../MessageBarActions/MessageBarActions'; +import { resetIdsForTests } from '@fluentui/react-utilities'; describe('MessageBar', () => { beforeAll(() => { @@ -23,6 +24,10 @@ describe('MessageBar', () => { }; }); + beforeEach(() => { + resetIdsForTests(); + }); + isConformant({ Component: MessageBar, displayName: 'MessageBar', diff --git a/packages/react-components/react-message-bar-preview/src/components/MessageBar/__snapshots__/MessageBar.test.tsx.snap b/packages/react-components/react-message-bar-preview/src/components/MessageBar/__snapshots__/MessageBar.test.tsx.snap index 17d8f7e24e3eaa..d59182d881ee5b 100644 --- a/packages/react-components/react-message-bar-preview/src/components/MessageBar/__snapshots__/MessageBar.test.tsx.snap +++ b/packages/react-components/react-message-bar-preview/src/components/MessageBar/__snapshots__/MessageBar.test.tsx.snap @@ -3,7 +3,9 @@ exports[`MessageBar renders a default state 1`] = `
Default MessageBarTitle