Skip to content

Commit 8eabe41

Browse files
authored
Announce callout contents in custom callout test (#3955)
* Edit announcement and add focusable element to callout * optimize custom callout example * Add back removed comment * restore yarn.lock file * Change files * debug PR pipeline * update debug code * restore pipeline file * debug * update xcode to 16.2.0 * revert xcode changes * update names for onclick and onkeydown handlers
1 parent 9a4efab commit 8eabe41

File tree

2 files changed

+47
-9
lines changed

2 files changed

+47
-9
lines changed

apps/fluent-tester/src/TestComponents/Callout/CalloutTest.tsx

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import type { KeyboardMetrics } from 'react-native';
3-
import { Text, View, Switch, ScrollView, Platform } from 'react-native';
3+
import { AccessibilityInfo, Platform, ScrollView, Switch, Text, View } from 'react-native';
44

55
import { ButtonV1 as Button, Separator, Pressable } from '@fluentui/react-native';
66
import type { IFocusable, RestoreFocusEvent, DismissBehaviors } from '@fluentui/react-native';
@@ -423,34 +423,63 @@ const StandardCallout: React.FunctionComponent = () => {
423423
const CustomCallout: React.FunctionComponent = () => {
424424
const [showCustomizedCallout, setShowCustomizedCallout] = React.useState(false);
425425
const [isCustomizedCalloutVisible, setIsCustomizedCalloutVisible] = React.useState(false);
426+
const [shouldFocusCloseButton, setShouldFocusCloseButton] = React.useState(false);
426427

427-
const toggleShowCustomizedCallout = React.useCallback(() => {
428-
setShowCustomizedCallout(!showCustomizedCallout);
428+
const a11yOnShowAnnouncement = 'Be informed that a customized callout has been opened.';
429+
const calloutMessage = 'This is an example message.';
430+
const closeButtonRef = React.useRef(null);
431+
432+
const openCallout = React.useCallback((focusCloseButton: boolean) => {
433+
setShowCustomizedCallout(true);
429434

430435
// Unmounting a callout does not invoke onDismiss; onDismiss is only invoked
431436
// for dismissals generated by the native app. When toggling to 'show',
432437
// the isVisible state will be corrected to 'true' by the onShow callback.
433438
setIsCustomizedCalloutVisible(false);
434-
}, [showCustomizedCallout, setIsCustomizedCalloutVisible, setShowCustomizedCallout]);
439+
setShouldFocusCloseButton(focusCloseButton);
440+
}, []);
441+
442+
const onClick = React.useCallback(() => {
443+
openCallout(false /*focusCloseButton*/);
444+
}, [openCallout]);
445+
446+
const onKeyDown = React.useCallback(
447+
(e) => {
448+
if (e.nativeEvent.key === 'Enter' || e.nativeEvent.key === ' ') {
449+
openCallout(true /*focusCloseButton*/);
450+
}
451+
},
452+
[openCallout],
453+
);
454+
455+
React.useEffect(() => {
456+
if (isCustomizedCalloutVisible && shouldFocusCloseButton) {
457+
closeButtonRef.current?.focus?.();
458+
}
459+
}, [isCustomizedCalloutVisible, shouldFocusCloseButton]);
435460

436461
const onShowCustomizedCallout = React.useCallback(() => {
437462
setIsCustomizedCalloutVisible(true);
438-
}, [setIsCustomizedCalloutVisible]);
463+
AccessibilityInfo.announceForAccessibility(a11yOnShowAnnouncement + ' ' + calloutMessage);
464+
}, []);
439465

440466
const onDismissCustomizedCallout = React.useCallback(() => {
441467
setIsCustomizedCalloutVisible(false);
442468

443469
// setting the internal state to false will instigate unmounting the
444470
// zombie Callout control.
445471
setShowCustomizedCallout(false);
446-
}, [setIsCustomizedCalloutVisible, setShowCustomizedCallout]);
472+
setShouldFocusCloseButton(false);
473+
}, []);
447474

448475
const myRect: KeyboardMetrics = { screenX: 10, screenY: 10, width: 100, height: 100 };
449476

450477
return (
451478
<View>
452479
<View style={{ flexDirection: 'column', paddingVertical: 5 }}>
453-
<Button onClick={toggleShowCustomizedCallout}>{'Press for Callout'}</Button>
480+
<Button onClick={onClick} onKeyDown={onKeyDown} onAccessibilityTap={() => openCallout(true)}>
481+
{'Press for Callout'}
482+
</Button>
454483
<Text selectable={true}>
455484
<Text>Visibility: </Text>
456485
{isCustomizedCalloutVisible ? <Text style={{ color: 'green' }}>Visible</Text> : <Text style={{ color: 'red' }}>Not Visible</Text>}
@@ -464,10 +493,12 @@ const CustomCallout: React.FunctionComponent = () => {
464493
onShow={onShowCustomizedCallout}
465494
accessibilityLabel="Customized Callout"
466495
accessibilityRole="alert"
467-
accessibilityOnShowAnnouncement="Be informed that a customized callout has been opened."
468496
>
469497
<View style={{ padding: 20, borderWidth: 2, borderColor: 'black' }}>
470-
<Text>just some text so it does not take focus and is not empty.</Text>
498+
<Text>{calloutMessage}</Text>
499+
<Button componentRef={closeButtonRef} onClick={onDismissCustomizedCallout}>
500+
{'Close'}
501+
</Button>
471502
</View>
472503
</Callout>
473504
)}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "Fix custom callout example",
4+
"packageName": "@fluentui-react-native/tester",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

0 commit comments

Comments
 (0)