@@ -81,6 +81,10 @@ export class FocusTrap {
8181 } ) ;
8282 }
8383
84+ focusInitialElementWhenReady ( ) {
85+ this . _ngZone . onMicrotaskEmpty . first ( ) . subscribe ( ( ) => this . focusInitialElement ( ) ) ;
86+ }
87+
8488 /**
8589 * Waits for microtask queue to empty, then focuses
8690 * the first tabbable element within the focus trap region.
@@ -97,27 +101,53 @@ export class FocusTrap {
97101 this . _ngZone . onMicrotaskEmpty . first ( ) . subscribe ( ( ) => this . focusLastTabbableElement ( ) ) ;
98102 }
99103
104+ /**
105+ * Get the specified boundary element of the trapped region.
106+ * @param bound The boundary to get (start or end of trapped region).
107+ * @returns The boundary element.
108+ */
109+ private _getRegionBoundary ( bound : 'start' | 'end' ) : HTMLElement | null {
110+ let markers = [
111+ ...Array . prototype . slice . call ( this . _element . querySelectorAll ( `[cdk-focus-region-${ bound } ]` ) ) ,
112+ // Deprecated version of selector, for temporary backwards comparability:
113+ ...Array . prototype . slice . call ( this . _element . querySelectorAll ( `[cdk-focus-${ bound } ]` ) ) ,
114+ ] ;
115+
116+ markers . forEach ( ( el : HTMLElement ) => {
117+ if ( el . hasAttribute ( `cdk-focus-${ bound } ` ) ) {
118+ console . warn ( `Found use of deprecated attribute 'cdk-focus-${ bound } ',` +
119+ ` use 'cdk-focus-region-${ bound } ' instead.` , el ) ;
120+ }
121+ } ) ;
122+
123+ if ( bound == 'start' ) {
124+ return markers . length ? markers [ 0 ] : this . _getFirstTabbableElement ( this . _element ) ;
125+ }
126+ return markers . length ?
127+ markers [ markers . length - 1 ] : this . _getLastTabbableElement ( this . _element ) ;
128+ }
129+
130+ /** Focuses the element that should be focused when the focus trap is initialized. */
131+ focusInitialElement ( ) {
132+ let redirectToElement = this . _element . querySelector ( '[cdk-focus-initial]' ) as HTMLElement ;
133+ if ( redirectToElement ) {
134+ redirectToElement . focus ( ) ;
135+ } else {
136+ this . focusFirstTabbableElement ( ) ;
137+ }
138+ }
139+
100140 /** Focuses the first tabbable element within the focus trap region. */
101141 focusFirstTabbableElement ( ) {
102- let redirectToElement = this . _element . querySelector ( '[cdk-focus-start]' ) as HTMLElement ||
103- this . _getFirstTabbableElement ( this . _element ) ;
104-
142+ let redirectToElement = this . _getRegionBoundary ( 'start' ) ;
105143 if ( redirectToElement ) {
106144 redirectToElement . focus ( ) ;
107145 }
108146 }
109147
110148 /** Focuses the last tabbable element within the focus trap region. */
111149 focusLastTabbableElement ( ) {
112- let focusTargets = this . _element . querySelectorAll ( '[cdk-focus-end]' ) ;
113- let redirectToElement : HTMLElement = null ;
114-
115- if ( focusTargets . length ) {
116- redirectToElement = focusTargets [ focusTargets . length - 1 ] as HTMLElement ;
117- } else {
118- redirectToElement = this . _getLastTabbableElement ( this . _element ) ;
119- }
120-
150+ let redirectToElement = this . _getRegionBoundary ( 'end' ) ;
121151 if ( redirectToElement ) {
122152 redirectToElement . focus ( ) ;
123153 }
0 commit comments