1+ import { FocusMonitor , FocusOrigin } from '@angular/cdk/a11y' ;
12import { AsyncPipe , NgClass } from '@angular/common' ;
23import {
34 ChangeDetectionStrategy ,
45 ChangeDetectorRef ,
56 Component ,
7+ DestroyRef ,
68 ElementRef ,
79 EventEmitter ,
810 inject ,
@@ -12,6 +14,7 @@ import {
1214 ViewChild ,
1315 ViewEncapsulation
1416} from '@angular/core' ;
17+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop' ;
1518import { FormControl , FormsModule , ReactiveFormsModule , UntypedFormControl , Validators } from '@angular/forms' ;
1619import { KbqAlertModule } from '@koobiq/components/alert' ;
1720import { KbqButton , KbqButtonModule , KbqButtonStyles } from '@koobiq/components/button' ;
@@ -60,6 +63,12 @@ import { KbqFilter, KbqSaveFilterError, KbqSaveFilterEvent, KbqSaveFilterStatuse
6063 }
6164} )
6265export class KbqFilters implements OnInit {
66+ /** @docs -private */
67+ protected readonly elementRef = inject ( ElementRef ) ;
68+ /** @docs -private */
69+ protected readonly destroyRef = inject ( DestroyRef ) ;
70+ /** @docs -private */
71+ protected readonly focusMonitor = inject ( FocusMonitor ) ;
6372 /** @docs -private */
6473 protected readonly placements = PopUpPlacements ;
6574 /** @docs -private */
@@ -73,9 +82,20 @@ export class KbqFilters implements OnInit {
7382 /** @docs -private */
7483 private readonly changeDetectorRef = inject ( ChangeDetectorRef ) ;
7584
76- @ViewChild ( KbqButton ) private button : KbqButton ;
77- @ViewChild ( KbqPopoverTrigger ) private popover : KbqPopoverTrigger ;
78- @ViewChild ( KbqDropdownTrigger ) private dropdown : KbqDropdownTrigger ;
85+ /** @docs -private */
86+ @ViewChild ( 'mainButton' ) protected mainButton : KbqButton ;
87+ /** @docs -private */
88+ @ViewChild ( 'saveNewFilterButton' ) protected saveNewFilterButton : KbqButton ;
89+ /** @docs -private */
90+ @ViewChild ( 'filterActionsButton' ) protected filterActionsButton : KbqButton ;
91+
92+ /** @docs -private */
93+ @ViewChild ( KbqPopoverTrigger ) protected popover : KbqPopoverTrigger ;
94+ /** @docs -private */
95+ @ViewChild ( KbqDropdownTrigger ) protected dropdown : KbqDropdownTrigger ;
96+ /** @docs -private */
97+ @ViewChild ( 'filterActionsButton' ) protected filterActionsDropdown : KbqDropdownTrigger ;
98+
7999 @ViewChild ( 'search' ) private search : ElementRef ;
80100 @ViewChild ( 'newFilterName' ) private newFilterName : ElementRef ;
81101 @ViewChild ( 'saveFilterButton' ) private saveFilterButton : KbqButton ;
@@ -125,6 +145,11 @@ export class KbqFilters implements OnInit {
125145 return this . popover ?. isOpen || this . dropdown ?. opened ;
126146 }
127147
148+ /** Component state. true if opened dropdown or popup of filterActions */
149+ get filterActionsOpened ( ) : boolean {
150+ return this . popover ?. isOpen || this . filterActionsDropdown ?. opened ;
151+ }
152+
128153 /** Selected filter */
129154 get filter ( ) : KbqFilter | null {
130155 return this . filterBar . filter ;
@@ -141,6 +166,16 @@ export class KbqFilters implements OnInit {
141166 return this . filterBar . configuration . filters ;
142167 }
143168
169+ /** Current focus origin state.
170+ * @docs -private */
171+ get focusOrigin ( ) : FocusOrigin {
172+ return this . _focusOrigin ;
173+ }
174+
175+ private _focusOrigin : FocusOrigin = null ;
176+
177+ private focusedElementBeforeOpen : KbqButton | null ;
178+
144179 constructor ( ) {
145180 this . filterBar . changes . subscribe ( ( ) => this . changeDetectorRef . markForCheck ( ) ) ;
146181 }
@@ -150,6 +185,19 @@ export class KbqFilters implements OnInit {
150185 of ( this . filters ) ,
151186 this . searchControl . valueChanges . pipe ( map ( ( value ) => this . getFilteredOptions ( value ) ) )
152187 ) ;
188+
189+ this . focusMonitor
190+ . monitor ( this . elementRef , true )
191+ . pipe (
192+ filter ( ( origin ) => ! ! origin ) ,
193+ takeUntilDestroyed ( this . destroyRef )
194+ )
195+ . subscribe ( ( origin ) => ( this . _focusOrigin = origin ) ) ;
196+ }
197+
198+ /** @docs -private */
199+ focusedElementBeforeIs ( button : KbqButton ) : boolean {
200+ return this . focusedElementBeforeOpen === button ;
153201 }
154202
155203 selectFilter ( filter : KbqFilter ) {
@@ -210,7 +258,10 @@ export class KbqFilters implements OnInit {
210258 }
211259
212260 restoreFocus ( ) {
213- this . button . focus ( ) ;
261+ if ( this . focusedElementBeforeOpen && ! this . focusedElementBeforeOpen . disabled ) {
262+ this . focusMonitor . focusVia ( this . focusedElementBeforeOpen . elementRef , this . focusOrigin ) ;
263+ this . focusedElementBeforeOpen = null ;
264+ }
214265 }
215266
216267 preparePopover ( ) {
@@ -221,11 +272,19 @@ export class KbqFilters implements OnInit {
221272 this . popover . show ( ) ;
222273
223274 merge ( ...this . popover . defaultClosingActions ( ) )
224- . pipe ( filter ( ( ) => ! this . isSaving ) )
275+ . pipe (
276+ filter ( ( ) => ! this . isSaving ) ,
277+ takeUntilDestroyed ( this . popover . instanceDestroyRef )
278+ )
279+ . subscribe ( ( ) => this . closePopover ( false ) ) ;
280+
281+ this . popover . visibleChange
282+ . pipe (
283+ filter ( ( state ) => ! state ) ,
284+ takeUntilDestroyed ( this . popover . instanceDestroyRef )
285+ )
225286 . subscribe ( this . closePopover ) ;
226287
227- this . popover . visibleChange . pipe ( filter ( ( state ) => ! state ) ) . subscribe ( this . closePopover ) ;
228-
229288 setTimeout ( ( ) => {
230289 this . newFilterName . nativeElement . focus ( ) ;
231290 this . filterName . setErrors ( null ) ;
@@ -244,10 +303,15 @@ export class KbqFilters implements OnInit {
244303 this . preparePopover ( ) ;
245304 }
246305
247- closePopover = ( ) => {
306+ /** @docs -private */
307+ saveFocusedElement ( button ?: KbqButton ) {
308+ this . focusedElementBeforeOpen = button || null ;
309+ }
310+
311+ closePopover = ( restoreFocus : boolean = true ) => {
248312 this . popover . hide ( ) ;
249313
250- this . restoreFocus ( ) ;
314+ if ( restoreFocus ) this . restoreFocus ( ) ;
251315
252316 setTimeout ( ( ) => this . changeDetectorRef . detectChanges ( ) ) ;
253317
@@ -280,6 +344,12 @@ export class KbqFilters implements OnInit {
280344 this . onResetFilterChanges . emit ( this . filter ! ) ;
281345 }
282346
347+ removeFilter ( ) {
348+ this . onRemoveFilter . next ( this . filter ! ) ;
349+
350+ setTimeout ( ( ) => this . focusMonitor . focusVia ( this . mainButton . elementRef , this . focusOrigin ) , 0 ) ;
351+ }
352+
283353 /** Hide the popup and restore focus.
284354 * Use this method in the onSave, onSaveAsNew, or onChangeFilter events after the data has been successfully saved. */
285355 filterSavedSuccessfully ( ) {
0 commit comments