Skip to content

Commit

Permalink
feat(various): use CDK FocusMonitor for keyboard focus style (#143)
Browse files Browse the repository at this point in the history
* feat(notification-panel): use CDK FocusMonitor for keyboard focus style

* feat(file-uploader): use CDK FocusMonitor for keyboard focus style

* feat(popover): use CDK FocusMonitor for keyboard focus style

* docs(popover): use CDK FocusMonitor in examples

* refactor(progress-indicator): add todo comment about navigation + focus
  • Loading branch information
snoopy-cat authored and GitHub Enterprise committed Dec 10, 2020
1 parent f068094 commit 587d86d
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
.btn-spacing{
margin-right: 10px;
}

:host-context([data-whatinput="mouse"]) nx-icon:focus {
nx-icon.cdk-mouse-focused {
outline: none;
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
<nx-icon name="refresh" size="s" [nxPopoverTriggerFor]='progress' nxPopoverDirection="top" nxPopoverTrigger="hover"
tabindex="0" role="button" aria-label="progress"></nx-icon>
<nx-icon #hoverTriggerIcon
name="refresh"
size="s"
[nxPopoverTriggerFor]='progress'
nxPopoverDirection="top"
nxPopoverTrigger="hover"
tabindex="0"
role="button"
aria-label="progress">
</nx-icon>

<nx-popover #progress>
Your application status is in progress.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Component } from '@angular/core';
import { FocusMonitor } from '@angular/cdk/a11y';
import { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild } from '@angular/core';

/**
* @title Popover Hover Example
Expand All @@ -8,6 +9,18 @@ import { Component } from '@angular/core';
templateUrl: './popover-hover-example.html',
styleUrls: ['./popover-hover-example.css']
})
export class PopoverHoverExampleComponent {
export class PopoverHoverExampleComponent implements AfterViewInit, OnDestroy {
popoverManualOpenFlag = false;

@ViewChild('hoverTriggerIcon') _hoverTriggerIcon: ElementRef<HTMLElement>;

constructor(private _focusMonitor: FocusMonitor) {}

ngAfterViewInit() {
this._focusMonitor.monitor(this._hoverTriggerIcon);
}

ngOnDestroy() {
this._focusMonitor.stopMonitoring(this._hoverTriggerIcon);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ nx-icon:hover {
color: var(--hover-primary, #3bb4db);
}

:host-context([data-whatinput="mouse"]) nx-icon:focus {
nx-icon.cdk-mouse-focused {
outline: none;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<p>
<nx-icon aria-label="trigger by click" name="info-circle-o" size="s" [nxPopoverTriggerFor]="popoverClick"
nxPopoverTrigger="click" tabindex="0"
<nx-icon #clickTriggerIcon
aria-label="trigger by click"
name="info-circle-o"
size="s"
[nxPopoverTriggerFor]="popoverClick"
nxPopoverTrigger="click"
tabindex="0"
role="button">
</nx-icon>
Triggered by click
Expand All @@ -10,10 +15,18 @@
</nx-popover>

<p>
<nx-icon name="info-circle-o" size="s" #popoverTrigger="nxPopoverTrigger" [nxPopoverTriggerFor]="popoverManual"
[(nxPopoverShow)]="popoverManualOpenFlag" nxPopoverDirection="top"
(click)="popoverManualOpenFlag = !popoverManualOpenFlag" (keydown)="handleKeydown($event)" nxPopoverTrigger="manual"
tabindex="0" aria-label="trigger manually"
<nx-icon #manualTriggerIcon
name="info-circle-o"
size="s"
#popoverTrigger="nxPopoverTrigger"
[nxPopoverTriggerFor]="popoverManual"
[(nxPopoverShow)]="popoverManualOpenFlag"
nxPopoverDirection="top"
(click)="popoverManualOpenFlag = !popoverManualOpenFlag"
(keydown)="handleKeydown($event)"
nxPopoverTrigger="manual"
tabindex="0"
aria-label="trigger manually"
role="button">
</nx-icon>
Triggered manually
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component } from '@angular/core';
import { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild } from '@angular/core';
import { SPACE, ENTER } from '@angular/cdk/keycodes';
import { FocusMonitor } from '@angular/cdk/a11y';

/**
* @title Popover Trigger Example
Expand All @@ -9,8 +10,24 @@ import { SPACE, ENTER } from '@angular/cdk/keycodes';
templateUrl: './popover-trigger-example.html',
styleUrls: ['./popover-trigger-example.css']
})
export class PopoverTriggerExampleComponent {
export class PopoverTriggerExampleComponent implements AfterViewInit, OnDestroy {
popoverManualOpenFlag = false;

@ViewChild('clickTriggerIcon') _clickTriggerIcon: ElementRef<HTMLElement>;
@ViewChild('manualTriggerIcon') _manualTriggerIcon: ElementRef<HTMLElement>;

constructor(private _focusMonitor: FocusMonitor) {}

ngAfterViewInit() {
this._focusMonitor.monitor(this._clickTriggerIcon);
this._focusMonitor.monitor(this._manualTriggerIcon);
}

ngOnDestroy() {
this._focusMonitor.stopMonitoring(this._clickTriggerIcon);
this._focusMonitor.stopMonitoring(this._manualTriggerIcon);
}

handleKeydown(event) {
switch (event.keyCode) {
case SPACE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
<div class="nx-file-uploader--file-list nx-margin-bottom-m"
role="listbox"
>
<div class="nx-file-uploader--file-row"
<div #fileRowElement
class="nx-file-uploader--file-row"
[class.nx-file-uploader--file-state-uploading]="file.isUploading"
*ngFor="let file of value"
role="option"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
display: block;
}

:host-context([data-whatinput="keyboard"]) .nx-file-uploader--file-row:focus {
.nx-file-uploader--file-row.cdk-keyboard-focused {
@include focus-style;
}

26 changes: 23 additions & 3 deletions projects/ng-aquila/src/file-uploader/file-uploader.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
AfterContentInit,
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Expand All @@ -16,7 +17,8 @@ import {
Output,
QueryList,
Self,
ViewChild
ViewChild,
ViewChildren
} from '@angular/core';
import { ErrorStateMatcher } from '@aposin/ng-aquila/utils';
import {
Expand All @@ -39,6 +41,7 @@ import { NxErrorComponent } from '@aposin/ng-aquila/base';
import { DOWN_ARROW, UP_ARROW } from '@angular/cdk/keycodes';
import { NxFileUploaderDropZoneComponent } from './file-uploader-drop-zone.component';
import { NxFileUploader } from './file-uploader';
import { FocusMonitor } from '@angular/cdk/a11y';

let nextId = 0;

Expand All @@ -55,7 +58,7 @@ let nextId = 0;
})

export class NxFileUploaderComponent implements ControlValueAccessor, AfterContentInit, OnChanges,
OnDestroy, DoCheck, OnInit {
OnDestroy, DoCheck, OnInit, AfterViewInit {

/** @docs-private */
@ContentChild(NxFileUploaderButtonDirective, {static: false}) button: NxFileUploaderButtonDirective;
Expand All @@ -75,6 +78,11 @@ export class NxFileUploaderComponent implements ControlValueAccessor, AfterConte
/** @docs-private */
@ContentChildren(NxErrorComponent) _errorList: QueryList<NxErrorComponent>;

@ViewChildren('fileRowElement') _fileRowElements: QueryList<ElementRef>;

/** Preserves the current value of the _fileRowElements ViewChildren in case _fileRowElements changes. */
private _fileRowElementsPrevious: QueryList<ElementRef>;

private _subscriptions: Subscription[] = [];
private _filesSubscriptions: Subscription[] = [];

Expand Down Expand Up @@ -218,7 +226,8 @@ export class NxFileUploaderComponent implements ControlValueAccessor, AfterConte
public _intl: NxFileUploaderIntl,
@Optional() private _parentForm: NgForm,
@Optional() private _parentFormGroup: FormGroupDirective,
/** @docs-private */ @Optional() @Self() public ngControl: NgControl) {
/** @docs-private */ @Optional() @Self() public ngControl: NgControl,
private _focusMonitor: FocusMonitor) {
if (this.ngControl) {
// Note: we provide the value accessor through here, instead of
// the `providers` to avoid running into a circular import.
Expand All @@ -240,6 +249,16 @@ export class NxFileUploaderComponent implements ControlValueAccessor, AfterConte
this._resetValidators();
}

ngAfterViewInit() {
this._fileRowElements.forEach(row => this._focusMonitor.monitor(row));
this._fileRowElementsPrevious = this._fileRowElements;
this._fileRowElements.changes.subscribe(rowElements => {
this._fileRowElementsPrevious.forEach(row => this._focusMonitor.stopMonitoring(row));
this._fileRowElementsPrevious = rowElements;
rowElements.forEach(row => this._focusMonitor.monitor(row));
});
}

ngOnChanges() {
this.stateChanges.next();
}
Expand All @@ -249,6 +268,7 @@ export class NxFileUploaderComponent implements ControlValueAccessor, AfterConte
this._intlChanges.unsubscribe();
this._subscriptions.forEach((subscription: Subscription) => subscription.unsubscribe());
this._filesSubscriptions.forEach((subscription: Subscription) => subscription.unsubscribe());
this._fileRowElements.forEach(row => this._focusMonitor.stopMonitoring(row));
}

/** @docs-private */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,62 +1,70 @@
@import "../../shared-styles/index";

:host {
display: flex;
flex-direction: column;
background-color: var(--notification-panel-item-unread-background-color);
padding: 16px 24px;
margin: 0 -24px;
&.nx-notification-item--read {
background-color: var(--notification-panel-item-read-background-color);
}
&:focus {
outline: none;
}
}
display: flex;
flex-direction: column;
background-color: var(--notification-panel-item-unread-background-color);
padding: 16px 24px;
margin: 0 -24px;

:host-context([data-whatinput="keyboard"]):focus {
&.nx-notification-item--read {
background-color: var(--notification-panel-item-read-background-color);
}

&:focus {
outline: none;
}

&.cdk-keyboard-focused {
@include focus-style-inset;
}
}

::ng-deep {
nx-notification-item-metadata {
font-size: 14px;
font-weight: 400;
line-height: 20px;
letter-spacing: 0.2px;
margin-bottom: 4px;
display: flex;
align-items: center;
}
nx-notification-item-content {
font-size: 16px;
font-weight: 400;
line-height: 24px;
}
nx-notification-item-actions {
font-size: 16px;
font-weight: 400;
line-height: 24px;
display: flex;
justify-content: space-between;
padding-top: 8px;
}
nx-notification-item-metadata {
font-size: 14px;
font-weight: 400;
line-height: 20px;
letter-spacing: 0.2px;
margin-bottom: 4px;
display: flex;
align-items: center;
}

nx-notification-item-content {
font-size: 16px;
font-weight: 400;
line-height: 24px;
}

nx-notification-item-actions {
font-size: 16px;
font-weight: 400;
line-height: 24px;
display: flex;
justify-content: space-between;
padding-top: 8px;
}
}

// Hover and active styles for clickable item
:host(.nx-notification-item--clickable) {
cursor: pointer;
cursor: pointer;
&:hover {
background-color: var(--notification-panel-item-unread-hover-background-color);
}

&:active {
background-color: var(--notification-panel-item-unread-active-background-color);
}

&.nx-notification-item--read {
&:hover {
background-color: var(--notification-panel-item-unread-hover-background-color);
background-color: var(--notification-panel-item-read-hover-background-color);
}

&:active {
background-color: var(--notification-panel-item-unread-active-background-color);
}
&.nx-notification-item--read {
&:hover {
background-color: var(--notification-panel-item-read-hover-background-color);
}
&:active {
background-color: var(-notification-panel-item-read-active-background-color);
}
background-color: var(-notification-panel-item-read-active-background-color);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FocusableOption, FocusOrigin } from '@angular/cdk/a11y';
import { FocusableOption, FocusMonitor, FocusOrigin } from '@angular/cdk/a11y';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { Component, ElementRef, Input } from '@angular/core';
import { Component, ElementRef, Input, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';

@Component({
Expand All @@ -16,7 +16,7 @@ import { Subject } from 'rxjs';
}
})

export class NxNotificationPanelItemComponent implements FocusableOption {
export class NxNotificationPanelItemComponent implements FocusableOption, OnDestroy {

private _read: boolean = false;
private _clickable: boolean = true;
Expand All @@ -40,7 +40,16 @@ export class NxNotificationPanelItemComponent implements FocusableOption {
return this._clickable;
}

constructor(private _elementRef: ElementRef) { }
constructor(
private _elementRef: ElementRef,
private _focusMonitor: FocusMonitor
) {
this._focusMonitor.monitor(this._elementRef);
}

ngOnDestroy() {
this._focusMonitor.stopMonitoring(this._elementRef);
}

focus(focusOrigin?: FocusOrigin) {
// the focus key manager calls this method with the focusOrigin
Expand All @@ -50,6 +59,7 @@ export class NxNotificationPanelItemComponent implements FocusableOption {
if (typeof focusOrigin === 'undefined' && !this._hasFocus) {
this.focused.next(this);
this._hasFocus = true;
this._focusMonitor.focusVia(this._elementRef, 'keyboard');
}

if (!this._hasFocus) {
Expand Down
Loading

0 comments on commit 587d86d

Please sign in to comment.