Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions packages/core/src/components/workflow-step/workflow-step.scss
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@
}

&:focus-visible {
outline: 1px solid var(--focus--border-color);
border-radius: 0;
outline: 1px solid var(--theme-color-focus-bdr);
outline-offset: var(--theme-btn--focus--outline-offset);
}

&.selected {
Expand Down
26 changes: 21 additions & 5 deletions packages/core/src/components/workflow-step/workflow-step.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,13 @@
@Event() selectedChanged!: EventEmitter<HTMLIxWorkflowStepElement>;

private customIconSlot: boolean = false;

private getStepLabel() {
return (
this.hostElement.ariaLabel ||
this.hostElement.textContent?.trim() ||
undefined
);
}
Comment thread
lakshmi-priya-b marked this conversation as resolved.
Outdated
@Watch('selected')
selectedHandler() {
this.setWorkflowStepStyles();
Expand Down Expand Up @@ -139,7 +145,12 @@
this.selectedChanged.emit(this.hostElement);
}
}

onKeyDown(event: KeyboardEvent) {
if (event.key === ' ' || event.key === 'Enter') {
event.preventDefault();
this.onStepClick();
}
}
getIconAriaLabel() {
switch (this.iconName) {
case iconCircle:
Expand Down Expand Up @@ -171,6 +182,7 @@
}
class="absolute"
size="24"
aria-hidden="true"
></ix-icon>
<ix-icon
color={this.iconColor}
Expand All @@ -181,22 +193,26 @@
></ix-icon>
</Fragment>
) : null;

return (
<Host
role="listitem"
class={{ 'host-vertical': this.vertical }}
onClick={() => this.onStepClick()}
aria-label={`${this.getStepLabel()}, ${this.status}`}
aria-current={this.selected ? 'step' : undefined}
aria-disabled={this.disabled ? 'true' : undefined}
>

Check warning on line 203 in packages/core/src/components/workflow-step/workflow-step.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

The attribute aria-disabled is not supported by the role listitem.

See more on https://sonarcloud.io/project/issues?id=siemens_ix&issues=AZ9Lm3OCSKDaIjQbyAKL&open=AZ9Lm3OCSKDaIjQbyAKL&pullRequest=2647
<div
tabIndex={0}
tabIndex={this.clickable && !this.disabled ? 0 : -1}
onClick={() => this.onStepClick()}
onKeyDown={(event: KeyboardEvent) => this.onKeyDown(event)}
class={{
step: true,
selected: this.selected,
vertical: this.vertical,
disabled: this.disabled,
clickable: this.clickable && !this.disabled,
}}
>

Check warning on line 215 in packages/core/src/components/workflow-step/workflow-step.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Avoid non-native interactive elements. If using native HTML is not possible, add an appropriate role and support for tabbing, mouse, keyboard, and touch inputs to an interactive content element.

See more on https://sonarcloud.io/project/issues?id=siemens_ix&issues=AZ9Lm3OCSKDaIjQbyAKM&open=AZ9Lm3OCSKDaIjQbyAKM&pullRequest=2647
<div class="wrapper">
<div
class={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,39 @@ regressionTest('renders', async ({ mount, page }) => {
await expect(step).toBeVisible();
});

regressionTest('accessibility', async ({ mount, makeAxeBuilder }) => {
await mount(`
<ix-workflow-steps>
<ix-workflow-step status="done">Step 1</ix-workflow-step>
<ix-workflow-step status="success">Step 2</ix-workflow-step>
<ix-workflow-step status="open">Step 3</ix-workflow-step>
</ix-workflow-steps>
`);

const results = await makeAxeBuilder().analyze();
expect(results.violations).toEqual([]);
});

regressionTest(
'has correct aria roles and default label',
async ({ mount, page }) => {
await mount(`
<ix-workflow-steps>
<ix-workflow-step>Step 1</ix-workflow-step>
<ix-workflow-step>Step 2</ix-workflow-step>
</ix-workflow-steps>
`);

const container = page.locator('ix-workflow-steps');
const steps = page.locator('ix-workflow-step');

await expect(container).toHaveAttribute('role', 'list');
await expect(container).toHaveAttribute('aria-label', 'Step indicator');
await expect(steps.nth(0)).toHaveAttribute('role', 'listitem');
await expect(steps.nth(1)).toHaveAttribute('role', 'listitem');
}
);

regressionTest('should be clickable', async ({ mount, page }) => {
await mount(`
<ix-workflow-steps clickable>
Expand Down Expand Up @@ -73,6 +106,28 @@ regressionTest('should prevent click navigation', async ({ mount, page }) => {
await expect(firstStepDiv).toHaveClass(/selected/);
await expect(lastStepDiv).not.toHaveClass(/selected/);
});
regressionTest(
'supports keyboard selection via Enter and Space',
async ({ mount, page }) => {
await mount(`
<ix-workflow-steps clickable>
<ix-workflow-step>Step 1</ix-workflow-step>
<ix-workflow-step>Step 2</ix-workflow-step>
</ix-workflow-steps>
`);

const first = page.locator('ix-workflow-step').nth(0).locator('.step');
const second = page.locator('ix-workflow-step').nth(1).locator('.step');

await first.focus();
await first.press('Enter');
await expect(first).toHaveClass(/selected/);

await second.focus();
await second.press('Space');
await expect(second).toHaveClass(/selected/);
}
);

regressionTest(
'should have the correct visuals after toggling state from open to error and back again to open',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
Listen,
Prop,
} from '@stencil/core';
import { A11yAttributes, a11yHostAttributes } from '../utils/a11y';
import { createMutationObserver } from '../utils/mutation-observer';

@Component({
Expand Down Expand Up @@ -47,6 +48,8 @@ export class WorkflowSteps {
*/
@Event() stepSelected!: EventEmitter<number>;

private inheritAriaAttributes: A11yAttributes = {};

private getSteps() {
return Array.from(this.hostElement.querySelectorAll('ix-workflow-step'));
}
Expand Down Expand Up @@ -93,6 +96,7 @@ export class WorkflowSteps {
}

componentWillLoad() {
this.inheritAriaAttributes = a11yHostAttributes(this.hostElement);
this.updateSteps();
}
Comment thread
lakshmi-priya-b marked this conversation as resolved.

Expand All @@ -119,8 +123,11 @@ export class WorkflowSteps {
}

render() {
this.inheritAriaAttributes['aria-label'] =
this.inheritAriaAttributes['aria-label'] ?? 'Step indicator';

return (
<Host>
<Host {...this.inheritAriaAttributes} role="list">
<div class={{ steps: true, vertical: this.vertical }}>
<slot></slot>
</div>
Expand Down
Loading