11import * as React from 'react' ;
22import 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
55import { ButtonV1 as Button , Separator , Pressable } from '@fluentui/react-native' ;
66import type { IFocusable , RestoreFocusEvent , DismissBehaviors } from '@fluentui/react-native' ;
@@ -423,34 +423,63 @@ const StandardCallout: React.FunctionComponent = () => {
423423const 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 ) }
0 commit comments