Skip to content

Commit

Permalink
Feature #13742 Add StepModel interface for step component accessibili…
Browse files Browse the repository at this point in the history
…ty improvements
  • Loading branch information
GiacomoDM committed Oct 12, 2023
1 parent 54d3d0f commit 2648248
Show file tree
Hide file tree
Showing 13 changed files with 60 additions and 39 deletions.
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>

0 comments on commit 2648248

Please sign in to comment.