Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CQI #13742 Step aria-controls showcase #13745

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/app/components/api/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export * from './selectitemgroup';
export * from './shared';
export * from './sortevent';
export * from './sortmeta';
export * from './stepitem';
export * from './tablestate';
export * from './translation';
export * from './translationkeys';
Expand Down
12 changes: 12 additions & 0 deletions src/app/components/api/stepitem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { MenuItem } from './menuitem';

/**
* StepItem provides all the properties from MenuItem, plus some custom ones.
* @group Interface
*/
export interface StepItem extends MenuItem {
/**
* Id of the controlled element. Allows to set the aria-controls attribute for the step. Note that the id of the controlled element must be set manually in the controlled element.
*/
ariaControls?: string;
}
39 changes: 21 additions & 18 deletions src/app/components/steps/steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Even
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
import { DomHandler } from 'primeng/dom';
import { Nullable } from 'primeng/ts-helpers';
import { MenuItem } from 'primeng/api';
import { StepItem } from 'primeng/api';
import { TooltipModule } from 'primeng/tooltip';
import { Subscription } from 'rxjs';
/**
Expand All @@ -18,15 +18,15 @@ import { Subscription } from 'rxjs';
<li
*ngFor="let item of model; let i = index"
class="p-steps-item"
#menuitem
#stepitem
[ngStyle]="item.style"
[class]="item.styleClass"
role="presentation"
[attr.id]="item.id"
pTooltip
[tooltipOptions]="item.tooltipOptions"
[ngClass]="{ 'p-highlight p-steps-current': isActive(item, i), 'p-disabled': item.disabled || (readonly && !isActive(item, i)) }"
[attr.data-pc-section]="'menuitem'"
[attr.data-pc-section]="'stepitem'"
>
<a
*ngIf="isClickableRouterLink(item); else elseBlock"
Expand All @@ -40,6 +40,7 @@ import { Subscription } from 'rxjs';
(keydown)="onItemKeydown($event, item, i)"
[target]="item.target"
[attr.tabindex]="getItemTabIndex(item, i)"
[attr.aria-controls]="item.ariaControls"
[attr.aria-selected]="i === activeIndex"
[attr.aria-expanded]="i === activeIndex"
[attr.aria-disabled]="item.disabled || (readonly && i !== activeIndex)"
Expand All @@ -64,6 +65,7 @@ import { Subscription } from 'rxjs';
(keydown)="onItemKeydown($event, item, i)"
[target]="item.target"
[attr.tabindex]="getItemTabIndex(item, i)"
[attr.aria-controls]="item.ariaControls"
[attr.aria-selected]="i === activeIndex"
[attr.aria-expanded]="i === activeIndex"
[attr.aria-disabled]="item.disabled || (readonly && i !== activeIndex)"
Expand Down Expand Up @@ -92,10 +94,11 @@ export class Steps implements OnInit, OnDestroy {
*/
@Input() activeIndex: number = 0;
/**
* An array of menu items.
* An array of step items, that extends MenuItem
* @see {MenuItem}
* @group Props
*/
@Input() model: MenuItem[] | undefined;
@Input() model: StepItem[] | undefined;
/**
* Whether the items are clickable or not.
* @group Props
Expand Down Expand Up @@ -133,7 +136,7 @@ export class Steps implements OnInit, OnDestroy {
this.subscription = this.router.events.subscribe(() => this.cd.markForCheck());
}

onItemClick(event: Event, item: MenuItem, i: number) {
onItemClick(event: Event, item: StepItem, i: number) {
if (this.readonly || item.disabled) {
event.preventDefault();
return;
Expand All @@ -154,7 +157,7 @@ export class Steps implements OnInit, OnDestroy {
}
}

onItemKeydown(event: KeyboardEvent, item: MenuItem, i: number) {
onItemKeydown(event: KeyboardEvent, item: StepItem, i: number) {
switch (event.code) {
case 'ArrowRight': {
this.navigateToNextItem(event.target);
Expand Down Expand Up @@ -182,7 +185,7 @@ export class Steps implements OnInit, OnDestroy {

case 'Tab':
if (i !== this.activeIndex) {
const siblings = DomHandler.find(this.listViewChild.nativeElement, '[data-pc-section="menuitem"]');
const siblings = DomHandler.find(this.listViewChild.nativeElement, '[data-pc-section="stepitem"]');
siblings[i].children[0].tabIndex = '-1';
siblings[this.activeIndex].children[0].tabIndex = '0';
}
Expand All @@ -203,22 +206,22 @@ export class Steps implements OnInit, OnDestroy {
navigateToNextItem(target) {
const nextItem = this.findNextItem(target);

nextItem && this.setFocusToMenuitem(target, nextItem);
nextItem && this.setFocusToStepitem(target, nextItem);
}
navigateToPrevItem(target) {
const prevItem = this.findPrevItem(target);

prevItem && this.setFocusToMenuitem(target, prevItem);
prevItem && this.setFocusToStepitem(target, prevItem);
}
navigateToFirstItem(target) {
const firstItem = this.findFirstItem();

firstItem && this.setFocusToMenuitem(target, firstItem);
firstItem && this.setFocusToStepitem(target, firstItem);
}
navigateToLastItem(target) {
const lastItem = this.findLastItem();

lastItem && this.setFocusToMenuitem(target, lastItem);
lastItem && this.setFocusToStepitem(target, lastItem);
}
findNextItem(item) {
const nextItem = item.parentElement.nextElementSibling;
Expand All @@ -231,26 +234,26 @@ export class Steps implements OnInit, OnDestroy {
return prevItem ? prevItem.children[0] : null;
}
findFirstItem() {
const firstSibling = DomHandler.findSingle(this.listViewChild.nativeElement, '[data-pc-section="menuitem"]');
const firstSibling = DomHandler.findSingle(this.listViewChild.nativeElement, '[data-pc-section="stepitem"]');

return firstSibling ? firstSibling.children[0] : null;
}
findLastItem() {
const siblings = DomHandler.find(this.listViewChild.nativeElement, '[data-pc-section="menuitem"]');
const siblings = DomHandler.find(this.listViewChild.nativeElement, '[data-pc-section="stepitem"]');

return siblings ? siblings[siblings.length - 1].children[0] : null;
}
setFocusToMenuitem(target, focusableItem) {
setFocusToStepitem(target, focusableItem) {
target.tabIndex = '-1';
focusableItem.tabIndex = '0';
focusableItem.focus();
}

isClickableRouterLink(item: MenuItem) {
isClickableRouterLink(item: StepItem) {
return item.routerLink && !this.readonly && !item.disabled;
}

isActive(item: MenuItem, index: number) {
isActive(item: StepItem, index: number) {
if (item.routerLink) {
let routerLink = Array.isArray(item.routerLink) ? item.routerLink : [item.routerLink];

Expand All @@ -260,7 +263,7 @@ export class Steps implements OnInit, OnDestroy {
return index === this.activeIndex;
}

getItemTabIndex(item: MenuItem, index: number): string {
getItemTabIndex(item: StepItem, index: number): string {
if (item.disabled) {
return '-1';
}
Expand Down
5 changes: 3 additions & 2 deletions src/app/showcase/doc/steps/accessibilitydoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { Component, Input } from '@angular/core';
<app-docsectiontext [title]="title" [id]="id">
<h3>Screen Reader</h3>
<p>
Steps component uses the <i>nav</i> element and since any attribute is passed to the root implicitly <i>aria-labelledby</i> or <i>aria-label</i> can be used to describe the component. Inside an ordered list is used where the current
step item defines <i>aria-current</i> as "step".
Steps component uses the <i>nav</i> element and since any attribute is passed to the root implicitly <i>aria-labelledby</i> or <i>aria-label</i> can be used to describe the component. Inside a list is used where the current step item
defines <i>aria-current</i> as "step". Each step have an <i>aria-controls</i> attribute, if the corresponding property is present in the step model, that links the step item to the controlled element, satisfying the WAI-ARIA
requirements for elements with <i>role=tablist</i>
</p>
<h3>Keyboard Support</h3>
<div class="doc-tablewrapper">
Expand Down
6 changes: 3 additions & 3 deletions src/app/showcase/doc/steps/basicdoc.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Component, Input, OnInit } from '@angular/core';
import { MenuItem } from 'primeng/api';
import { StepItem } from 'primeng/api';
import { Code } from '../../domain/code';

@Component({
selector: 'basic-doc',
template: ` <section class="py-4">
<app-docsectiontext [title]="title" [id]="id">
<p>Steps requires a collection of menuitems as its <i>model</i>.</p>
<p>Steps requires a collection of stepitems as its <i>model</i>.</p>
</app-docsectiontext>
<div class="card">
<p-steps [model]="items" [readonly]="true"></p-steps>
Expand All @@ -19,7 +19,7 @@ export class BasicDoc implements OnInit {

@Input() title: string;

items: MenuItem[] | undefined;
items: StepItem[] | undefined;

ngOnInit() {
this.items = [
Expand Down
2 changes: 1 addition & 1 deletion src/app/showcase/doc/steps/confirmationdemo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Router } from '@angular/router';

@Component({
template: `
<div class="stepsdemo-content">
<div class="stepsdemo-content" id="confirmation-content">
<p-card>
<ng-template pTemplate="title"> Confirmation </ng-template>
<ng-template pTemplate="subtitle"> Enter your card details </ng-template>
Expand Down
4 changes: 2 additions & 2 deletions src/app/showcase/doc/steps/interactivedoc.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Input, OnInit } from '@angular/core';
import { MenuItem, MessageService } from 'primeng/api';
import { StepItem, MessageService } from 'primeng/api';
import { Code } from '../../domain/code';

@Component({
Expand All @@ -21,7 +21,7 @@ export class InteractiveDoc implements OnInit {

@Input() title: string;

items: MenuItem[] | undefined;
items: StepItem[] | undefined;

activeIndex: number = 0;

Expand Down
2 changes: 1 addition & 1 deletion src/app/showcase/doc/steps/paymentdemo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Router } from '@angular/router';

@Component({
template: `
<div class="stepsdemo-content">
<div class="stepsdemo-content" id="payment-content">
<p-card>
<ng-template pTemplate="title"> Payment Information </ng-template>
<ng-template pTemplate="subtitle"> Enter your card details </ng-template>
Expand Down
2 changes: 1 addition & 1 deletion src/app/showcase/doc/steps/personaldemo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Router } from '@angular/router';

@Component({
template: `
<div class="stepsdemo-content">
<div class="stepsdemo-content" id="personal-content">
<p-card>
<ng-template pTemplate="title"> Personal Information </ng-template>
<ng-template pTemplate="subtitle"> Enter your personal information </ng-template>
Expand Down
16 changes: 10 additions & 6 deletions src/app/showcase/doc/steps/routingdoc.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Input, OnInit } from '@angular/core';
import { MenuItem, MessageService } from 'primeng/api';
import { StepItem, MessageService } from 'primeng/api';
import { Subscription } from 'rxjs';
import { Code } from '../../domain/code';
import { TicketService } from '../../service/ticketservice';
Expand All @@ -24,7 +24,7 @@ export class RoutingDoc implements OnInit {

@Input() title: string;

items: MenuItem[];
items: StepItem[];

subscription: Subscription;

Expand All @@ -34,19 +34,23 @@ export class RoutingDoc implements OnInit {
this.items = [
{
label: 'Personal',
routerLink: ''
routerLink: '',
ariaControls: 'personal-content'
},
{
label: 'Seat',
routerLink: 'seat'
routerLink: 'seat',
ariaControls: 'seat-content'
},
{
label: 'Payment',
routerLink: 'payment'
routerLink: 'payment',
ariaControls: 'payment-content'
},
{
label: 'Confirmation',
routerLink: 'confirmation'
routerLink: 'confirmation',
ariaControls: 'confirmation-content'
}
];

Expand Down
2 changes: 1 addition & 1 deletion src/app/showcase/doc/steps/seatdemo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Router } from '@angular/router';

@Component({
template: `
<div class="stepsdemo-content">
<div class="stepsdemo-content" id="seat-content">
<p-card>
<ng-template pTemplate="title"> Seat Information </ng-template>
<ng-template pTemplate="subtitle"> Choose your seat </ng-template>
Expand Down
6 changes: 3 additions & 3 deletions src/app/showcase/doc/steps/styledoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ import { Component, Input } from '@angular/core';
</tr>
<tr>
<td>p-steps-item</td>
<td>Menuitem element.</td>
<td>StepItem element.</td>
</tr>
<tr>
<td>p-steps-number</td>
<td>Number of menuitem.</td>
<td>Number of StepItem.</td>
</tr>
<tr>
<td>p-steps-title</td>
<td>Label of menuitem.</td>
<td>Label of StepItem.</td>
</tr>
</tbody>
</table>
Expand Down
2 changes: 1 addition & 1 deletion src/app/showcase/pages/steps/stepsdemo.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<app-doc docTitle="Angular Steps Component" header="Steps" description="Steps also known as Stepper, is an indicator for the steps in a workflow. Layout of steps component is optimized for responsive design." [docs]="docs" [apiDocs]="['Steps', 'MenuItem']"></app-doc>
<app-doc docTitle="Angular Steps Component" header="Steps" description="Steps also known as Stepper, is an indicator for the steps in a workflow. Layout of steps component is optimized for responsive design." [docs]="docs" [apiDocs]="['Steps', 'StepItem']"></app-doc>
Loading