mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
demo(list): Add accessibility demo page for list (#7020)
* demo(list): Add accessibility demo page for list * fix test * set default role for md-list * fix test * Add template file for list
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
||||
} from './dialog/dialog-a11y';
|
||||
import {ExpansionPanelAccessibilityDemo} from './expansion/expansion-a11y';
|
||||
import {GridListAccessibilityDemo} from './grid-list/grid-list-a11y';
|
||||
import {ListAccessibilityDemo} from './list/list-a11y';
|
||||
import {RadioAccessibilityDemo} from './radio/radio-a11y';
|
||||
import {ToolbarAccessibilityDemo} from './toolbar/toolbar-a11y';
|
||||
import {DatepickerAccessibilityDemo} from './datepicker/datepicker-a11y';
|
||||
@@ -93,6 +94,7 @@ export class AccessibilityRoutingModule {}
|
||||
GridListAccessibilityDemo,
|
||||
IconAccessibilityDemo,
|
||||
InputAccessibilityDemo,
|
||||
ListAccessibilityDemo,
|
||||
MenuAccessibilityDemo,
|
||||
ProgressBarAccessibilityDemo,
|
||||
ProgressSpinnerAccessibilityDemo,
|
||||
|
||||
@@ -49,6 +49,7 @@ export class AccessibilityDemo implements OnDestroy {
|
||||
{name: 'Grid list', route: 'grid-list'},
|
||||
{name: 'Icon', route: 'icon'},
|
||||
{name: 'Input', route: 'input'},
|
||||
{name: 'List', route: 'list'},
|
||||
{name: 'Menu', route: 'menu'},
|
||||
{name: 'Progress bar', route: 'progress-bar'},
|
||||
{name: 'Progress spinner', route: 'progress-spinner'},
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<div class="demo-list">
|
||||
<section>
|
||||
<h2> Seasoning </h2>
|
||||
<p>Showing a non-interactive list of seasonings.</p>
|
||||
<mat-list role="list">
|
||||
<mat-list-item *ngFor="let item of items"> {{item}} </mat-list-item>
|
||||
</mat-list>
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<h2>Mailbox navigation</h2>
|
||||
<p>Showing a navigation list with links to google search</p>
|
||||
<mat-nav-list>
|
||||
<a mat-list-item *ngFor="let link of links"
|
||||
href="https://www.google.com/search?q={{link.name}}">
|
||||
{{link.name}}
|
||||
</a>
|
||||
</mat-nav-list>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Messages</h2>
|
||||
<p>
|
||||
Showing a list of messages, where each message item has sender's name, sender's avatar,
|
||||
message subject, and content of the message.
|
||||
</p>
|
||||
<mat-list role="list">
|
||||
<mat-list-item *ngFor="let message of messages">
|
||||
<img mat-list-avatar [src]="message.image" [alt]="message.from">
|
||||
<h3 mat-line> {{message.from}} </h3>
|
||||
<p mat-line> {{message.subject}} </p>
|
||||
<p mat-line class="demo-secondary-text"> {{message.message}} </p>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Seasoning</h2>
|
||||
<p>Showing a non-interactive list of seasonings with dense style.</p>
|
||||
<mat-list dense>
|
||||
<mat-list-item *ngFor="let item of items"> {{item}} </mat-list-item>
|
||||
</mat-list>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Folders and notes for mailbox </h2>
|
||||
<p>Showing a list with two sections, "folders" and "notes".</p>
|
||||
<mat-list role="list">
|
||||
<h3 mat-subheader>Folders</h3>
|
||||
<mat-list-item *ngFor="let folder of folders">
|
||||
<mat-icon mat-list-icon>folder</mat-icon>
|
||||
<h4 mat-line>{{folder.name}}</h4>
|
||||
<p mat-line class="demo-secondary-text"> {{folder.updated}} </p>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
<h3 mat-subheader>Notes</h3>
|
||||
<mat-list-item *ngFor="let note of notes">
|
||||
<mat-icon mat-list-icgon>note</mat-icon>
|
||||
<h4 mat-line>{{note.name}}</h4>
|
||||
<p mat-line class="demo-secondary-text"> {{note.updated}} </p>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</section>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
.demo-list {
|
||||
.mat-list, .mat-nav-list {
|
||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||
max-width: 350px;
|
||||
margin: 20px 20px 0 0;
|
||||
}
|
||||
|
||||
.demo-secondary-text {
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'list-a11y',
|
||||
templateUrl: 'list-a11y.html',
|
||||
styleUrls: ['list-a11y.css']
|
||||
})
|
||||
export class ListAccessibilityDemo {
|
||||
items: string[] = [
|
||||
'Pepper',
|
||||
'Salt',
|
||||
'Paprika'
|
||||
];
|
||||
|
||||
messages = [
|
||||
{
|
||||
from: 'Nancy',
|
||||
subject: 'Brunch?',
|
||||
message: 'Did you want to go on Sunday? I was thinking that might work.',
|
||||
image: 'https://angular.io/generated/images/bios/julie-ralph.jpg'
|
||||
},
|
||||
{
|
||||
from: 'Mary',
|
||||
subject: 'Summer BBQ',
|
||||
message: 'Wish I could come, but I have some prior obligations.',
|
||||
image: 'https://angular.io/generated/images/bios/juleskremer.jpg'
|
||||
},
|
||||
{
|
||||
from: 'Bobby',
|
||||
subject: 'Oui oui',
|
||||
message: 'Do you have Paris reservations for the 15th? I just booked!',
|
||||
image: 'https://angular.io/generated/images/bios/jelbourn.jpg'
|
||||
}
|
||||
];
|
||||
|
||||
links = [
|
||||
{name: 'Inbox'},
|
||||
{name: 'Outbox'},
|
||||
{name: 'Spam'},
|
||||
{name: 'Trash'}
|
||||
|
||||
];
|
||||
|
||||
folders = [
|
||||
{name: 'Imported', updated: 'Miles'},
|
||||
{name: 'Important', updated: 'Tina'},
|
||||
{name: 'Unread', updated: 'Jeremy'},
|
||||
];
|
||||
|
||||
notes = [
|
||||
{name: 'Update screenshots', updated: 'Kara'},
|
||||
{name: 'Install new application', updated: 'Andrew'},
|
||||
];
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import {ToolbarAccessibilityDemo} from './toolbar/toolbar-a11y';
|
||||
import {DatepickerAccessibilityDemo} from './datepicker/datepicker-a11y';
|
||||
import {IconAccessibilityDemo} from './icon/icon-a11y';
|
||||
import {InputAccessibilityDemo} from './input/input-a11y';
|
||||
import {ListAccessibilityDemo} from './list/list-a11y';
|
||||
import {MenuAccessibilityDemo} from './menu/menu-a11y';
|
||||
import {ProgressBarAccessibilityDemo} from './progress-bar/progress-bar-a11y';
|
||||
import {ProgressSpinnerAccessibilityDemo} from './progress-spinner/progress-spinner-a11y';
|
||||
@@ -52,6 +53,7 @@ export const ACCESSIBILITY_DEMO_ROUTES: Routes = [
|
||||
{path: 'grid-list', component: GridListAccessibilityDemo},
|
||||
{path: 'icon', component: IconAccessibilityDemo},
|
||||
{path: 'input', component: InputAccessibilityDemo},
|
||||
{path: 'list', component: ListAccessibilityDemo},
|
||||
{path: 'menu', component: MenuAccessibilityDemo},
|
||||
{path: 'progress-bar', component: ProgressBarAccessibilityDemo},
|
||||
{path: 'progress-spinner', component: ProgressSpinnerAccessibilityDemo},
|
||||
|
||||
@@ -17,13 +17,12 @@ import {
|
||||
import {
|
||||
MatDividerCssMatStyler,
|
||||
MatList,
|
||||
MatNavList,
|
||||
MatListAvatarCssMatStyler,
|
||||
MatListCssMatStyler,
|
||||
MatListDivider,
|
||||
MatListIconCssMatStyler,
|
||||
MatListItem,
|
||||
MatListSubheaderCssMatStyler,
|
||||
MatNavListCssMatStyler,
|
||||
} from './list';
|
||||
import {MatListOption, MatSelectionList} from './selection-list';
|
||||
|
||||
@@ -32,14 +31,13 @@ import {MatListOption, MatSelectionList} from './selection-list';
|
||||
imports: [MatLineModule, MatRippleModule, MatCommonModule, MatPseudoCheckboxModule, CommonModule],
|
||||
exports: [
|
||||
MatList,
|
||||
MatNavList,
|
||||
MatListItem,
|
||||
MatListDivider,
|
||||
MatListAvatarCssMatStyler,
|
||||
MatLineModule,
|
||||
MatCommonModule,
|
||||
MatListIconCssMatStyler,
|
||||
MatListCssMatStyler,
|
||||
MatNavListCssMatStyler,
|
||||
MatDividerCssMatStyler,
|
||||
MatListSubheaderCssMatStyler,
|
||||
MatPseudoCheckboxModule,
|
||||
@@ -48,12 +46,11 @@ import {MatListOption, MatSelectionList} from './selection-list';
|
||||
],
|
||||
declarations: [
|
||||
MatList,
|
||||
MatNavList,
|
||||
MatListItem,
|
||||
MatListDivider,
|
||||
MatListAvatarCssMatStyler,
|
||||
MatListIconCssMatStyler,
|
||||
MatListCssMatStyler,
|
||||
MatNavListCssMatStyler,
|
||||
MatDividerCssMatStyler,
|
||||
MatListSubheaderCssMatStyler,
|
||||
MatSelectionList,
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<ng-content></ng-content>
|
||||
|
||||
@@ -150,3 +150,12 @@ To add a divider, use `<mat-divider>`.
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
```
|
||||
|
||||
### Accessibility
|
||||
By default, the list assumes that it will be used in a purely decorative fashion and thus sets no
|
||||
roles, ARIA attributes, or keyboard shortcuts. This is equivalent to having a sequence of <div>
|
||||
elements on the page. Any interactive content within the list should be given an appropriate
|
||||
accessibility treatment based on the specific workflow of your application.
|
||||
|
||||
If the list is used to present a list of non-interactive content items, then the list element should
|
||||
be given `role="list"` and each list item should be given `role="listitem"`.
|
||||
|
||||
@@ -115,7 +115,7 @@ describe('MatList', () => {
|
||||
|
||||
let list = fixture.debugElement.children[0];
|
||||
let listItem = fixture.debugElement.children[0].query(By.css('mat-list-item'));
|
||||
expect(list.nativeElement.getAttribute('role')).toBe('list');
|
||||
expect(list.nativeElement.getAttribute('role')).toBeNull();
|
||||
expect(listItem.nativeElement.getAttribute('role')).toBe('listitem');
|
||||
});
|
||||
|
||||
|
||||
+24
-28
@@ -44,10 +44,27 @@ export class MatListDivider {}
|
||||
/** A Material Design list component. */
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'mat-list, mat-nav-list',
|
||||
exportAs: 'matList, matNavList',
|
||||
host: {'role': 'list'},
|
||||
template: '<ng-content></ng-content>',
|
||||
selector: 'mat-nav-list',
|
||||
exportAs: 'matNavList',
|
||||
host: {
|
||||
'role': 'navigation',
|
||||
'class': 'mat-nav-list'
|
||||
},
|
||||
templateUrl: 'list.html',
|
||||
styleUrls: ['list.css'],
|
||||
inputs: ['disableRipple'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
preserveWhitespaces: false,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class MatNavList extends _MatListMixinBase implements CanDisableRipple {}
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'mat-list',
|
||||
exportAs: 'matList',
|
||||
templateUrl: 'list.html',
|
||||
host: {'class': 'mat-list'},
|
||||
styleUrls: ['list.css'],
|
||||
inputs: ['disableRipple'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
@@ -56,26 +73,6 @@ export class MatListDivider {}
|
||||
})
|
||||
export class MatList extends _MatListMixinBase implements CanDisableRipple {}
|
||||
|
||||
/**
|
||||
* Directive whose purpose is to add the mat- CSS styling to this selector.
|
||||
* @docs-private
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'mat-list',
|
||||
host: {'class': 'mat-list'}
|
||||
})
|
||||
export class MatListCssMatStyler {}
|
||||
|
||||
/**
|
||||
* Directive whose purpose is to add the mat- CSS styling to this selector.
|
||||
* @docs-private
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'mat-nav-list',
|
||||
host: {'class': 'mat-nav-list'}
|
||||
})
|
||||
export class MatNavListCssMatStyler {}
|
||||
|
||||
/**
|
||||
* Directive whose purpose is to add the mat- CSS styling to this selector.
|
||||
* @docs-private
|
||||
@@ -150,10 +147,9 @@ export class MatListItem extends _MatListItemMixinBase implements AfterContentIn
|
||||
}
|
||||
|
||||
constructor(private _element: ElementRef,
|
||||
@Optional() private _list: MatList,
|
||||
@Optional() navList: MatNavListCssMatStyler) {
|
||||
@Optional() private _navList: MatNavList) {
|
||||
super();
|
||||
this._isNavList = !!navList;
|
||||
this._isNavList = !!_navList;
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
@@ -162,7 +158,7 @@ export class MatListItem extends _MatListItemMixinBase implements AfterContentIn
|
||||
|
||||
/** Whether this list item should show a ripple effect when clicked. */
|
||||
_isRippleDisabled() {
|
||||
return !this._isNavList || this.disableRipple || this._list.disableRipple;
|
||||
return !this._isNavList || this.disableRipple || this._navList.disableRipple;
|
||||
}
|
||||
|
||||
_handleFocus() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<mat-list>
|
||||
<mat-list role="list">
|
||||
<mat-list-item>Item 1</mat-list-item>
|
||||
<mat-list-item>Item 2</mat-list-item>
|
||||
<mat-list-item>Item 3</mat-list-item>
|
||||
|
||||
Reference in New Issue
Block a user