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

fix(components/popovers): screen readers can navigate to popover contents #2672

Closed
wants to merge 19 commits 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
5 changes: 4 additions & 1 deletion .eslintrc-overrides.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@
"@angular-eslint/template/no-any": ["error"],
"@angular-eslint/template/no-call-expression": ["warn"],
"@angular-eslint/template/no-distracting-elements": ["warn"],
"@angular-eslint/template/no-inline-styles": ["warn"],
"@angular-eslint/template/no-inline-styles": [
"warn",
{ "allowBindToStyle": true, "allowNgStyle": true }
Blackbaud-SteveBrush marked this conversation as resolved.
Show resolved Hide resolved
],
"@angular-eslint/template/no-interpolation-in-attributes": ["warn"],
"@angular-eslint/template/no-positive-tabindex": ["warn"],
"@angular-eslint/template/prefer-control-flow": ["warn"],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,18 @@
<button
class="sky-btn sky-btn-default sky-margin-inline-sm"
data-sky-id="popover-demo"
type="button"
[skyPopover]="myPopover"
[skyPopoverAlignment]="popoverAlignment"
[skyPopoverPlacement]="popoverPlacement"
data-sky-id="popover-demo"
>
Open popover on click
</button>

<button
class="sky-btn sky-btn-link"
type="button"
[skyPopover]="myPopover"
skyPopoverTrigger="mouseenter"
>
Open popover on hover
Open popover
</button>

<sky-popover
#myPopover
[dismissOnBlur]="dismissOnBlur"
[popoverTitle]="popoverTitle"
#myPopover
>
{{ popoverBody }}
</sky-popover>
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<div class="sky-help-inline-demo">
<h2>
Giving
With popover
<sky-help-inline
ariaControls="popover"
popoverContent="This is a popoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopoverpopover"
popoverTitle="Did you knowccc?"
>
</sky-help-inline>
labelText="foo"
popoverContent="This is a popover."
popoverTitle="Did you know?"
/>
</h2>
<h2>
With help key
<sky-help-inline helpKey="foo.html" labelText="bar" />
</h2>
</div>
Original file line number Diff line number Diff line change
@@ -1,15 +1,47 @@
import { ChangeDetectorRef, Component, inject } from '@angular/core';
import {
ChangeDetectorRef,
Component,
Injectable,
inject,
} from '@angular/core';
import { SKY_HELP_GLOBAL_OPTIONS, SkyHelpService } from '@skyux/core';

import { Observable, of } from 'rxjs';

@Injectable()
class DemoHelpService extends SkyHelpService {
public override get widgetReadyStateChange(): Observable<boolean> {
return of(true);
}

public override openHelp(): void {
alert('Help opened!');
}
}

@Component({
selector: 'app-help-inline',
templateUrl: './help-inline.component.html',
providers: [
{
provide: SKY_HELP_GLOBAL_OPTIONS,
useValue: {
ariaControls: 'foo-id',
ariaHaspopup: 'modal',
},
},
{
provide: SkyHelpService,
useClass: DemoHelpService,
},
],
})
export class HelpInlineComponent {
public popoverOpen = false;

#changeDetector = inject(ChangeDetectorRef);
readonly #changeDetector = inject(ChangeDetectorRef);

public popoverChange(isOpen): void {
public popoverChange(isOpen: boolean): void {
this.popoverOpen = isOpen;
this.#changeDetector.markForCheck();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,54 @@
type="button"
[skyPopover]="myPopover0"
>
Popover demo on click
Open popover with interactive content
</button>

<button
Blackbaud-SteveBrush marked this conversation as resolved.
Show resolved Hide resolved
class="sky-btn sky-btn-primary sky-margin-inline-default"
type="button"
[skyPopover]="myPopover1"
>
Only text
</button>

<button
class="sky-btn sky-btn-link"
type="button"
[skyPopover]="myPopover0"
[skyPopover]="myPopover2"
[skyPopoverTrigger]="'mouseenter'"
>
Popover demo on hover
Show on hover
</button>

<sky-popover popoverTitle="Playground popover" #myPopover0>
The content of a popover can be text, HTML, or Angular components.
</sky-popover>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque ut velit
a urna fermentum fermentum. Quisque sed lectus sit amet nibh tempus
fermentum ac eget lorem. Mauris lorem nisl, finibus ut turpis vitae,
venenatis faucibus nibh. Phasellus laoreet elit ac sagittis tincidunt. Sed
finibus, sem nec convallis condimentum, nulla odio mattis sem, venenatis
rhoncus neque nisi quis quam. Ut quis aliquet eros. Fusce quis mauris
tellus. Ut pharetra mi sed nisi pharetra, sit amet bibendum leo cursus.
Maecenas bibendum risus vestibulum nisl sagittis, vitae fermentum nibh
facilisis. Nunc luctus vehicula ex ac aliquam. Suspendisse sodales iaculis
nibh id condimentum.
</p>

<p>
<button type="button">Some action</button>
</p>
</sky-page-content>
</sky-page>

<sky-popover #myPopover0 popoverTitle="Playground popover">
The content of a popover can be text, HTML, or Angular components.
<button type="button">Subscribe</button>
</sky-popover>

<sky-popover #myPopover1>
The content of a popover can be text, HTML, or Angular components.
</sky-popover>

<sky-popover #myPopover2>
The content of a popover can be text, HTML, or Angular components.
</sky-popover>
1 change: 0 additions & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ module.exports = () => {
jasmine: {
random: false,
},
clearContext: false, // leave Jasmine Spec Runner output visible in browser
},
coverageReporter: {
dir: join(__dirname, './coverage'),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<div
class="sky-validator-cell"
skyPopoverTrigger="mouseenter"
[skyPopover]="validatorPopover"
[skyPopoverMessageStream]="popoverMessageStream"
class="sky-validator-cell"
>
<ng-content />
<sky-status-indicator
descriptionType="none"
indicatorType="danger"
class="sky-pull-right"
></sky-status-indicator>
/>
</div>
<sky-popover #validatorPopover popoverType="danger">
{{ validatorMessage }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ describe('Checkbox harness', () => {
});
const helpSvc = TestBed.inject(SkyHelpService);
const helpSpy = spyOn(helpSvc, 'openHelp');
fixture.componentInstance.helpKey = 'helpKey.html';
fixture.componentInstance.helpPopoverContent = undefined;
fixture.detectChanges();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
[labelHidden]="hidePhoneLabel"
data-sky-id="my-phone-checkbox"
formControlName="phone"
helpKey="helpKey.html"
[helpKey]="helpKey"
helpPopoverContent="(xxx)xxx-xxxx"
helpPopoverTitle="Format"
labelText="Phone"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ describe('Field group harness', () => {
const helpSvc = TestBed.inject(SkyHelpService);
const helpSpy = spyOn(helpSvc, 'openHelp');

fixture.componentInstance.helpKey = 'helpKey.html';

await fieldGroupHarness.clickHelpInline();
fixture.detectChanges();
await fixture.whenStable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class FieldGroupComponent {
public headingHidden = false;
public headingLevel: SkyFieldGroupHeadingLevel = 3;
public headingStyle: SkyFieldGroupHeadingStyle = 3;
public helpKey: string | undefined = 'helpKey.html';
public helpKey: string | undefined;
public helpPopoverContent: string | undefined = 'Popover content';
public helpPopoverTitle = 'Popover title';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class InputBoxHarnessTestComponent {
public easyModeDisabled = false;
public easyModeHelpContent: string | TemplateRef<unknown> | undefined =
'Help content';
public easyModeHelpKey: string | undefined = 'helpKey.html';
public easyModeHelpKey: string | undefined;
public easyModeHelpTitle = 'Help title';
public easyModeLabel: string | undefined = 'Last name (easy mode)';
public easyModeStacked = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,19 +144,20 @@ describe('Input box harness', () => {
);
});

it('should open help popover and widget when clicked', async () => {
it('should open widget when clicked', async () => {
const { fixture, inputBoxHarness } = await setupTest({
dataSkyId: DATA_SKY_ID_EASY_MODE,
});

fixture.componentInstance.easyModeHelpKey = 'helpKey.html';

const helpSvc = TestBed.inject(SkyHelpService);
const helpSpy = spyOn(helpSvc, 'openHelp');

await inputBoxHarness.clickHelpInline();
fixture.detectChanges();
await fixture.whenStable();

await expectAsync(inputBoxHarness.getHelpPopoverContent()).toBeResolved();
expect(helpSpy).toHaveBeenCalledWith({ helpKey: 'helpKey.html' });
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Pipe, PipeTransform } from '@angular/core';

/**
* Sets the value of `aria-label` for inline help buttons.
* @internal
*/
@Pipe({
name: 'skyHelpInlineAriaLabel',
standalone: true,
})
export class SkyHelpInlineAriaLabelPipe implements PipeTransform {
public transform(
ariaLabel: string | undefined,
labelText: string | undefined,
labelledBy: string | undefined,
defaultAriaLabel: string | undefined,
): string | undefined {
if (labelledBy) {
return;
}

if (labelText) {
return labelText;
}

if (ariaLabel) {
return ariaLabel;
}

return defaultAriaLabel;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { CommonModule } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
inject,
input,
output,
} from '@angular/core';
import { SKY_HELP_GLOBAL_OPTIONS, SkyHelpService } from '@skyux/core';

/**
* @internal
*/
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule],
selector: 'sky-help-inline-help-key-button',
standalone: true,
styleUrls: [
'./help-inline.default.component.scss',
'./help-inline.modern.component.scss',
],
template: `
<button
class="sky-help-inline"
type="button"
[attr.aria-controls]="
((helpSvc?.widgetReadyStateChange | async)
? helpGlobalOptions?.ariaControls
: null) ?? ariaControls()
"
[attr.aria-haspopup]="helpGlobalOptions?.ariaHaspopup"
[attr.aria-label]="ariaLabel()"
[attr.aria-labelledby]="ariaLabelledby()"
[ngClass]="{
'sky-help-inline-hidden': !helpSvc
}"
(click)="openHelpKey()"
>
<ng-content />
</button>
`,
})
export class SkyHelpInlineHelpKeyButtonComponent {
public actionClick = output<void>();
public ariaControls = input<string | undefined>();
public ariaLabel = input<string | undefined>();
public ariaLabelledby = input<string | undefined>();
public helpKey = input.required<string>();

protected readonly helpGlobalOptions = inject(SKY_HELP_GLOBAL_OPTIONS, {
optional: true,
});

protected readonly helpSvc = inject(SkyHelpService, { optional: true });

protected openHelpKey(): void {
this.actionClick.emit();

this.helpSvc?.openHelp({
helpKey: this.helpKey(),
});
}
}
Loading
Loading