diff --git a/packages/cdk/a11y/key-manager/activedescendant-key-manager.ts b/packages/cdk/a11y/key-manager/activedescendant-key-manager.ts index 110108306..add4c6e86 100644 --- a/packages/cdk/a11y/key-manager/activedescendant-key-manager.ts +++ b/packages/cdk/a11y/key-manager/activedescendant-key-manager.ts @@ -49,5 +49,4 @@ export class ActiveDescendantKeyManager extends ListKeyManager { fixture.detectChanges(); flush(); - (overlayContainerElement.querySelectorAll('mc-tree-option')[2] as HTMLElement).click(); + const optionToClick = overlayContainerElement.querySelectorAll('mc-tree-option')[2] as HTMLElement; + optionToClick.focus(); + optionToClick.click(); fixture.detectChanges(); flush(); @@ -1722,7 +1724,8 @@ describe('McTreeSelect', () => { tick(10); expect(formControl.value).toBe('Documents'); - expect(fixture.componentInstance.options.toArray()[2].active).toBe(true); + expect(fixture.componentInstance.select.tree.keyManager.activeItem!.value) + .toBe('Documents'); })); it('should not shift focus when the selected options are updated programmatically ' + @@ -4581,6 +4584,7 @@ describe('McTreeSelect', () => { const options: NodeListOf = overlayContainerElement.querySelectorAll('mc-tree-option'); + options[2].focus(); options[2].click(); fixture.detectChanges(); flush(); diff --git a/packages/mosaic/tree/_tree-theme.scss b/packages/mosaic/tree/_tree-theme.scss index de3fea5cf..5312dc1d9 100644 --- a/packages/mosaic/tree/_tree-theme.scss +++ b/packages/mosaic/tree/_tree-theme.scss @@ -19,8 +19,7 @@ background-color: mc-color($background, hover); } - &.mc-focused, - &.mc-active { + &.mc-focused { border-color: mc-color($primary); } diff --git a/packages/mosaic/tree/tree-option.ts b/packages/mosaic/tree/tree-option.ts index 474f3b0a6..13c2464ee 100644 --- a/packages/mosaic/tree/tree-option.ts +++ b/packages/mosaic/tree/tree-option.ts @@ -18,6 +18,7 @@ import { CanDisable, toBoolean } from '@ptsecurity/mosaic/core'; export interface McTreeOptionParentComponent { multiple: boolean; selectionModel: SelectionModel; + setSelectedOption: any; setFocusedOption: any; } @@ -45,8 +46,10 @@ let uniqueIdCounter: number = 0; class: 'mc-tree-option', '[class.mc-selected]': 'selected', - '[class.mc-active]': 'active', + '[class.mc-focused]': 'hasFocus', + '(focus)': 'handleFocus()', + '(blur)': 'handleBlur()', '(click)': 'selectViaInteraction($event)' }, changeDetection: ChangeDetectionStrategy.OnPush, @@ -102,18 +105,6 @@ export class McTreeOption extends CdkTreeNode implements CanDisabl private _selected: boolean = false; - /** - * Whether or not the option is currently active and ready to be selected. - * An active option displays styles as if it is focused, but the - * focus is actually retained somewhere else. This comes in handy - * for components like autocomplete where focus must remain on the input. - */ - get active(): boolean { - return this._active; - } - - private _active = false; - get id(): string { return this._id; } @@ -124,6 +115,8 @@ export class McTreeOption extends CdkTreeNode implements CanDisabl return this.parent.multiple; } + hasFocus: boolean = false; + constructor( protected elementRef: ElementRef, protected changeDetectorRef: ChangeDetectorRef, @@ -151,28 +144,25 @@ export class McTreeOption extends CdkTreeNode implements CanDisabl this.changeDetectorRef.markForCheck(); } - /** - * This method sets display styles on the option to make it appear - * active. This is used by the ActiveDescendantKeyManager so key - * events will display the proper options as active on arrow key events. - */ - setActiveStyles(): void { - if (!this._active) { - this._active = true; + handleFocus() { + if (this.disabled || this.hasFocus) { return; } - this.changeDetectorRef.markForCheck(); + this.hasFocus = true; + + if (this.parent.setFocusedOption) { + this.parent.setFocusedOption(this); } } - /** - * This method removes display styles on the option that made it appear - * active. This is used by the ActiveDescendantKeyManager so key - * events will display the proper options as active on arrow key events. - */ - setInactiveStyles(): void { - if (this._active) { - this._active = false; - this.changeDetectorRef.markForCheck(); + handleBlur() { + this.hasFocus = false; + } + + focus(): void { + const element = this.getHostElement(); + + if (typeof element.focus === 'function') { + element.focus(); } } @@ -186,21 +176,6 @@ export class McTreeOption extends CdkTreeNode implements CanDisabl return 0; } - focus(): void { - const element = this.getHostElement(); - - if (typeof element.focus === 'function') { - element.focus(); - } - } - - // todo старая реализация, нужно восстановить tree-selection - // handleClick(): void { - // if (this.disabled) { return; } - // - // this.treeSelection.setFocusedOption(this); - // } - get viewValue(): string { // TODO: Add input property alternative for node envs. return (this.getHostElement().textContent || '').trim(); @@ -227,8 +202,8 @@ export class McTreeOption extends CdkTreeNode implements CanDisabl this.changeDetectorRef.markForCheck(); this.emitSelectionChangeEvent(true); - if (this.parent.setFocusedOption) { - this.parent.setFocusedOption(this, $event); + if (this.parent.setSelectedOption) { + this.parent.setSelectedOption(this, $event); } } } diff --git a/packages/mosaic/tree/tree-selection.ts b/packages/mosaic/tree/tree-selection.ts index e02f00a74..bcb4d9b25 100644 --- a/packages/mosaic/tree/tree-selection.ts +++ b/packages/mosaic/tree/tree-selection.ts @@ -20,7 +20,7 @@ import { } from '@angular/core'; import { NodeDef, ViewData } from '@angular/core/esm2015/src/view'; import { ControlValueAccessor, NgControl } from '@angular/forms'; -import { ActiveDescendantKeyManager } from '@ptsecurity/cdk/a11y'; +import { FocusKeyManager } from '@ptsecurity/cdk/a11y'; import { END, ENTER, @@ -97,7 +97,7 @@ export class McTreeSelection extends McTreeSelectionBaseMixin @ContentChildren(McTreeOption) options: QueryList; - keyManager: ActiveDescendantKeyManager; + keyManager: FocusKeyManager; selectionModel: SelectionModel; @@ -163,7 +163,7 @@ export class McTreeSelection extends McTreeSelectionBaseMixin } ngAfterContentInit(): void { - this.keyManager = new ActiveDescendantKeyManager(this.options) + this.keyManager = new FocusKeyManager(this.options) .withVerticalOrientation(true) .withHorizontalOrientation(null); @@ -256,9 +256,7 @@ export class McTreeSelection extends McTreeSelectionBaseMixin this.keyManager.withScrollSize(Math.floor(this.getHeight() / this.options.first.getHeight())); } - setFocusedOption(option: McTreeOption, $event?: KeyboardEvent) { - this.keyManager.setActiveItem(option); - + setSelectedOption(option: McTreeOption, $event?: KeyboardEvent) { const withShift = $event ? hasModifierKey($event, 'shiftKey') : false; const withCtrl = $event ? hasModifierKey($event, 'ctrlKey') : false; @@ -296,11 +294,15 @@ export class McTreeSelection extends McTreeSelectionBaseMixin } } + setFocusedOption(option: McTreeOption): void { + this.keyManager.setActiveItem(option); + } + toggleFocusedOption(): void { const focusedOption = this.keyManager.activeItem; if (focusedOption) { - this.setFocusedOption(focusedOption); + this.setSelectedOption(focusedOption); } }