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

feat: add assertive property to notification #7758

Merged
merged 1 commit into from
Sep 18, 2024
Merged
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
10 changes: 10 additions & 0 deletions packages/notification/src/vaadin-notification.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface NotificationCustomEventMap {
export interface NotificationEventMap extends HTMLElementEventMap, NotificationCustomEventMap {}

export interface ShowOptions {
assertive?: boolean;
duration?: number;
position?: NotificationPosition;
theme?: string;
Expand Down Expand Up @@ -116,13 +117,15 @@ declare class Notification extends OverlayClassMixin(ThemePropertyMixin(ElementM
*
* ```
* {
* assertive?: boolean
* position?: string
* duration?: number
* theme?: string
* }
* ```
*
* See the individual documentation for:
* - [`assertive`](#/elements/vaadin-notification#property-assertive)
* - [`position`](#/elements/vaadin-notification#property-position)
* - [`duration`](#/elements/vaadin-notification#property-duration)
*
Expand All @@ -131,6 +134,13 @@ declare class Notification extends OverlayClassMixin(ThemePropertyMixin(ElementM
*/
static show(contents: TemplateResult | string, options?: ShowOptions): Notification;

/**
* When true, the notification card has `aria-live` attribute set to
* `assertive` instead of `polite`. This makes screen readers announce
* the notification content immediately when it appears.
*/
assertive: boolean;

/**
* The duration in milliseconds to show the notification.
* Set to `0` or a negative number to disable the notification auto-closing.
Expand Down
26 changes: 24 additions & 2 deletions packages/notification/src/vaadin-notification.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ class NotificationCard extends ThemableMixin(PolymerElement) {
ready() {
super.ready();
this.setAttribute('role', 'alert');
this.setAttribute('aria-live', 'polite');
}
}

Expand Down Expand Up @@ -273,7 +272,10 @@ class Notification extends OverlayClassMixin(ThemePropertyMixin(ElementMixin(Pol
display: none !important;
}
</style>
<vaadin-notification-card theme$="[[_theme]]"> </vaadin-notification-card>
<vaadin-notification-card
theme$="[[_theme]]"
aria-live$="[[__computeAriaLive(assertive)]]"
></vaadin-notification-card>
`;
}

Expand All @@ -283,6 +285,16 @@ class Notification extends OverlayClassMixin(ThemePropertyMixin(ElementMixin(Pol

static get properties() {
return {
/**
* When true, the notification card has `aria-live` attribute set to
* `assertive` instead of `polite`. This makes screen readers announce
* the notification content immediately when it appears.
*/
assertive: {
type: Boolean,
value: false,
},

/**
* The duration in milliseconds to show the notification.
* Set to `0` or a negative number to disable the notification auto-closing.
Expand Down Expand Up @@ -340,13 +352,15 @@ class Notification extends OverlayClassMixin(ThemePropertyMixin(ElementMixin(Pol
*
* ```
* {
* assertive?: boolean
* position?: string
* duration?: number
* theme?: string
* }
* ```
*
* See the individual documentation for:
* - [`assertive`](#/elements/vaadin-notification#property-assertive)
* - [`position`](#/elements/vaadin-notification#property-position)
* - [`duration`](#/elements/vaadin-notification#property-duration)
*
Expand All @@ -373,6 +387,9 @@ class Notification extends OverlayClassMixin(ThemePropertyMixin(ElementMixin(Pol
if (options && options.position) {
notification.position = options.position;
}
if (options && options.assertive) {
notification.assertive = options.assertive;
}
if (options && options.theme) {
notification.setAttribute('theme', options.theme);
}
Expand Down Expand Up @@ -436,6 +453,11 @@ class Notification extends OverlayClassMixin(ThemePropertyMixin(ElementMixin(Pol
this.renderer(this._card, this);
}

/** @private */
__computeAriaLive(assertive) {
return assertive ? 'assertive' : 'polite';
}

/** @private */
_rendererChanged(renderer, opened, card) {
if (!card) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,14 @@ snapshots["vaadin-notification card class"] =
`;
/* end snapshot vaadin-notification card class */

snapshots["vaadin-notification assertive"] =
`<vaadin-notification-card
aria-live="assertive"
role="alert"
slot="bottom-start"
>
content
</vaadin-notification-card>
`;
/* end snapshot vaadin-notification assertive */

5 changes: 5 additions & 0 deletions packages/notification/test/dom/notification.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ describe('vaadin-notification', () => {
notification.overlayClass = 'custom';
await expect(card).dom.to.equalSnapshot();
});

it('assertive', async () => {
notification.assertive = true;
await expect(card).dom.to.equalSnapshot();
});
});
12 changes: 12 additions & 0 deletions packages/notification/test/notification.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,18 @@ describe('vaadin-notification', () => {
it('notification card should have `aria-live="polite"`', () => {
expect(notification._card.getAttribute('aria-live')).to.be.equal('polite');
});

it('should update `aria-live` to "assertive" when assertive is set to true', () => {
notification.assertive = true;
expect(notification._card.getAttribute('aria-live')).to.be.equal('assertive');
});

it('should update `aria-live` to "polite" when assertive is set to false', () => {
notification.assertive = true;

notification.assertive = false;
expect(notification._card.getAttribute('aria-live')).to.be.equal('polite');
});
});

describe('methods', () => {
Expand Down
5 changes: 5 additions & 0 deletions packages/notification/test/statichelper.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ describe('static helpers', () => {
expect(notification.position).to.equal('top-center');
});

it('show should use assertive property when set to true', () => {
const notification = Notification.show('Hello world', { assertive: true });
expect(notification.assertive).to.be.true;
});

it('show should set the given theme attribute', () => {
const notification = Notification.show('Hello world', { theme: 'error' });
expect(notification.getAttribute('theme')).to.equal('error');
Expand Down
3 changes: 2 additions & 1 deletion packages/notification/test/typings/notification.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ assertType<OverlayClassMixinClass>(notification);
assertType<ThemePropertyMixinClass>(notification);

// Properties
assertType<boolean>(notification.assertive);
assertType<number>(notification.duration);
assertType<boolean>(notification.opened);
assertType<NotificationPosition>(notification.position);
Expand All @@ -36,7 +37,7 @@ notification.addEventListener('closed', (event) => {
assertType<NotificationClosedEvent>(event);
});

Notification.show('Hello world', { position: 'middle', duration: 7000, theme: 'error' });
Notification.show('Hello world', { assertive: true, position: 'middle', duration: 7000, theme: 'error' });

const renderer: NotificationRenderer = (root, owner) => {
assertType<HTMLElement>(root);
Expand Down
Loading