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(alert-banner): add alert banner component #4266

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9b3175a
feat(alert-banner): create alert banner component
Apr 12, 2024
b387b39
feat(alert-banner): add alert-banner to elements bundle
Apr 12, 2024
1145fca
feat(alert-banner): add alert banner tokens in global vars
Apr 12, 2024
9bee350
feat(alert-banner): add stories
Apr 12, 2024
6caaa8c
feat(alert-banner): update readme
Apr 12, 2024
3ce0607
feat(alert-banner): add tests
Apr 12, 2024
ca1fd66
feat(alert-banner): use define element to register component
Apr 15, 2024
7401d7a
feat(alert-banner): add missing dependencies
Apr 15, 2024
ab2ecbe
feat(alert-banner): update golden image cache key
Apr 15, 2024
41cef88
feat(alert-banner): update package version
Apr 15, 2024
0e2fc28
feat(alert-banner): fix wrong import
Apr 15, 2024
7f3f056
feat(alert-banner): update readme
Apr 15, 2024
af13501
feat(alert-banner): address review feedback
Apr 24, 2024
41f49f8
Merge branch 'main' into lspataru/alert-banner
Apr 24, 2024
5909508
feat(alert-banner): update golden image hash
Apr 25, 2024
b6a83d2
feat(alert-banner): revert renovate file
Apr 25, 2024
7e33a0f
feat(alert-banner): add multilangiage story
Apr 25, 2024
af2c057
feat(alert-banner): update args
Apr 25, 2024
2d5adb5
Merge branch 'main' into lspataru/alert-banner
Apr 26, 2024
afac40f
feat(alert-banner): update golden image hash
Apr 26, 2024
706c622
feat(alert-banner): fix typo
Apr 30, 2024
8b83f2a
Merge branch 'main' into lspataru/alert-banner
Apr 30, 2024
7acf7e1
Merge branch 'main' into lspataru/alert-banner
May 22, 2024
8c26e20
feat(alert-banner): fix after main sync
May 22, 2024
6acd39c
feat(alert-banner): update spectrum-css version
May 23, 2024
db2cd1f
feat(alert-banner): update golden image hash
May 23, 2024
bd3765a
Merge branch 'main' into lspataru/alert-banner
loredanaspataru May 23, 2024
9a80f42
feat(alert-banner): revert hash
May 23, 2024
8630a16
feat(alert-banner): update golden image hash
May 23, 2024
780f478
Merge branch 'main' into lspataru/alert-banner
May 24, 2024
4e0978d
feat(alert-banner): update golden image hash
May 24, 2024
7aca227
feat(alert-banner): update global vars
May 24, 2024
4e3f7c2
Merge branch 'main' into lspataru/alert-banner
May 27, 2024
b8166a7
feat(alert-banner): update golden image hash
May 27, 2024
e39c453
feat(alert-banner): update readme
May 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Expand Up @@ -10,7 +10,7 @@ executors:
parameters:
current_golden_images_hash:
type: string
default: 884232c2b90bc74a3c348a6a92858bf8ed3f10a1
default: 2d5adb5e05375af03e9e32e7c4a8094a428abd5b
wireit_cache_name:
type: string
default: wireit
Expand Down
2 changes: 2 additions & 0 deletions packages/alert-banner/.npmignore
@@ -0,0 +1,2 @@
stories
test
97 changes: 97 additions & 0 deletions packages/alert-banner/README.md
@@ -0,0 +1,97 @@
## Description

The `sp-alert-banner` shows pressing and high-signal messages, such as system alerts. It is meant to be noticed and prompt users to take action.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The `sp-alert-banner` shows pressing and high-signal messages, such as system alerts. It is meant to be noticed and prompt users to take action.
The `<sp-alert-banner>` shows pressing and high-signal messages, such as system alerts. It is meant to be noticed and prompt users to take action.


### Usage

[![See it on NPM!](https://img.shields.io/npm/v/@spectrum-web-components/alert-banner?style=for-the-badge)](https://www.npmjs.com/package/@spectrum-web-components/alert-banner)
[![How big is this package in your project?](https://img.shields.io/bundlephobia/minzip/@spectrum-web-components/alert-banner?style=for-the-badge)](https://bundlephobia.com/result?p=@spectrum-web-components/alert-banner)

```
yarn add @spectrum-web-components/alert-banner
```

Import the side effectful registration of `<sp-alert-banner>` via:

```
import '@spectrum-web-components/alert-banner/sp-alert-banner.js';
```

When looking to leverage the `AlertBanner` base class as a type and/or for extension purposes, do so via:

```
import { AlertBanner } from '@spectrum-web-components/alert-banner';
```

## Examples

The alert banner accepts text context in the default slot provided:

```html
<sp-alert-banner open>
All documents in this folder have been archived
</sp-alert-banner>
```

### Dismissible

Use the `dismissible` attribute to include an icon-only close button to dismiss the alert banner:

```html
<sp-alert-banner open dismissible>
All documents in this folder have been archived
</sp-alert-banner>
```

### Actionable

Use the action slot for the contextual action that a user can take in response to the issue described:

```html
<sp-alert-banner open dismissible>
Your trial has expired
<sp-button treatment="outline" static="white" slot="action">
Buy now
</sp-button>
</sp-alert-banner>
```

## Variants

### Info

```html
<sp-alert-banner open variant="info" dismissible>
Your trial will expire in 3 days
<sp-button treatment="outline" static="white" slot="action">
Buy now
</sp-button>
</sp-alert-banner>
```

### Negative

```html
<sp-alert-banner open variant="negative" dismissible>
Connection interupted. Check your network to continue
</sp-alert-banner>
```

## Closing the alert banner

Alert banners should be used for system-level messages and they should be dismissed only as a result of a user action or if the internal state that triggered the alert has been resolved.

The alert can be dismissed by triggering the close button in case of a dismissible alert. It also exposes a public `close` method to allow consumers to close the alert programmatically.

The component dispatches a `close` event to announce that the alert banner has been closed. This can be prevented by using the `event.preventDefault()` API.

## Accesibility
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Accesibility
## Accessibility


loredanaspataru marked this conversation as resolved.
Show resolved Hide resolved
The `sp-alert-banner` element is rendered with a `role` of `alert`, to inform screen readers and notify users accordingly. When rendering the element on a page, it should be placed in a container with a `role` of `region`. The component should not interfere with the user’s current workflow by changing page focus.

The alert banner supports keyboard interaction as follows:

- _Tab_ should place focus on the next interactive element, which can be either the actionable button or the close button.
- _Tab + Shift_ should place focus on the previous interactive element.
- _Space_ or _Enter_ should trigger the interaction if one of the buttons is focused, thus dismissing the alert in case of the close button or triggering the corresponding contextual action.
- _Esc_ will dismiss an alert banner if it’s a dismissible alert.
4 changes: 4 additions & 0 deletions packages/alert-banner/exports.json
@@ -0,0 +1,4 @@
{
"./src/*": "./src/*.js",
"./sp-alert-banner.js": "./sp-alert-banner.js"
}
73 changes: 73 additions & 0 deletions packages/alert-banner/package.json
@@ -0,0 +1,73 @@
{
"name": "@spectrum-web-components/alert-banner",
"version": "0.0.1",
"publishConfig": {
"access": "public"
},
"description": "Web component implementation of a Spectrum design AlertBanner",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/adobe/spectrum-web-components.git",
"directory": "packages/alert-banner"
},
"author": "",
"homepage": "https://adobe.github.io/spectrum-web-components/components/alert-banner",
"bugs": {
"url": "https://github.com/adobe/spectrum-web-components/issues"
},
"main": "src/index.js",
"module": "src/index.js",
"type": "module",
"exports": {
".": {
"development": "./src/index.dev.js",
"default": "./src/index.js"
},
"./package.json": "./package.json",
"./src/AlertBanner.js": {
"development": "./src/AlertBanner.dev.js",
"default": "./src/AlertBanner.js"
},
"./src/alert-banner.css.js": "./src/alert-banner.css.js",
"./src/index.js": {
"development": "./src/index.dev.js",
"default": "./src/index.js"
},
"./sp-alert-banner.js": {
"development": "./sp-alert-banner.dev.js",
"default": "./sp-alert-banner.js"
}
},
"scripts": {
"test": "echo \"Error: run tests from mono-repo root.\" && exit 1"
},
"files": [
"**/*.d.ts",
"**/*.js",
"**/*.js.map",
"custom-elements.json",
"!stories/",
"!test/"
],
"keywords": [
"spectrum css",
"web components",
"lit-element",
"lit-html"
],
"dependencies": {
"@spectrum-web-components/base": "^0.42.2",
"@spectrum-web-components/button": "^0.42.2",
"@spectrum-web-components/icons-workflow": "^0.42.2"
},
"devDependencies": {
"@spectrum-css/alertbanner": "^1.1.39"
},
"types": "./src/index.d.ts",
"customElements": "custom-elements.json",
"sideEffects": [
"./sp-*.js",
"./**/*.dev.js"
]
}
21 changes: 21 additions & 0 deletions packages/alert-banner/sp-alert-banner.ts
@@ -0,0 +1,21 @@
/*
Copyright 2024 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/
import { AlertBanner } from './src/AlertBanner.js';
import { defineElement } from '@spectrum-web-components/base/src/define-element.js';

defineElement('sp-alert-banner', AlertBanner);

declare global {
interface HTMLElementTagNameMap {
'sp-alert-banner': AlertBanner;
}
}
176 changes: 176 additions & 0 deletions packages/alert-banner/src/AlertBanner.ts
@@ -0,0 +1,176 @@
/*
Copyright 2024 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/
import {
CSSResultArray,
html,
PropertyValues,
SpectrumElement,
TemplateResult,
} from '@spectrum-web-components/base';
import { property } from '@spectrum-web-components/base/src/decorators.js';
import '@spectrum-web-components/button/sp-close-button.js';
import '@spectrum-web-components/icons-workflow/icons/sp-icon-alert.js';
import '@spectrum-web-components/icons-workflow/icons/sp-icon-info.js';
import styles from './alert-banner.css.js';

const VALID_VARIANTS = ['neutral', 'info', 'negative'];
export type AlertBannerVariants = typeof VALID_VARIANTS[number];

/**
* @element sp-alert-banner
*
* @slot - The alert banner text context
* @slot action - Slot for the button element that surfaces the contextual action a user can take
*
* @fires close - Announces the alert banner has been closed
*/
export class AlertBanner extends SpectrumElement {
public static override get styles(): CSSResultArray {
return [styles];
}

/**
* Controls the display of the alert banner
*
* @param {Boolean} open
*/
@property({ type: Boolean, reflect: true })
public open = false;

/**
* Whether to include an icon-only close button to dismiss the alert banner
*
* @param {Boolean} dismissible
*/
@property({ type: Boolean, reflect: true })
public dismissible = false;

/**
* The variant applies specific styling when set to `negative` or `info`;
* `variant` attribute is removed when it's passed an invalid variant.
*
* @param {String} variant
*/
@property({ type: String })
public set variant(variant: AlertBannerVariants) {
if (variant === this.variant) {
return;
}
const oldValue = this.variant;

if (this.isValidVariant(variant)) {
this.setAttribute('variant', variant);
this._variant = variant;
} else {
this.removeAttribute('variant');
this._variant = '';

if (window.__swc.DEBUG) {
window.__swc.warn(
this,
`<${this.localName}> element expects the "variant" attribute to be one of the following:`,
'https://opensource.adobe.com/spectrum-web-components/components/alert-banner/#variants',
{
issues: [...VALID_VARIANTS],
}
);
}
}
this.requestUpdate('variant', oldValue);
}

public get variant(): AlertBannerVariants {
return this._variant;
}

private _variant: AlertBannerVariants = '';

protected isValidVariant(variant: string): boolean {
return VALID_VARIANTS.includes(variant);
}

protected renderIcon(variant: string): TemplateResult {
switch (variant) {
case 'info':
return html`
<sp-icon-info
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not customisable?

label="Information"
class="type"
></sp-icon-info>
`;
case 'negative':
return html`
<sp-icon-alert label="Error" class="type"></sp-icon-alert>
`;
default:
return html``;
}
}

private shouldClose(): void {
const applyDefault = this.dispatchEvent(
new CustomEvent('close', {
composed: true,
bubbles: true,
cancelable: true,
})
);
if (applyDefault) {
this.close();
}
}

public close(): void {
this.open = false;
}

private handleKeydown(event: KeyboardEvent): void {
if (event.code === 'Escape' && this.dismissible) {
this.shouldClose();
}
}

protected override render(): TemplateResult {
return html`
<div class="body" role="alert">
<div class="content">
${this.renderIcon(this.variant)}
<div class="text"><slot></slot></div>
</div>
<slot name="action"></slot>
loredanaspataru marked this conversation as resolved.
Show resolved Hide resolved
</div>
<div class="end">
${this.dismissible
? html`
<sp-close-button
@click=${this.shouldClose}
label="Close"
static="white"
loredanaspataru marked this conversation as resolved.
Show resolved Hide resolved
></sp-close-button>
`
: html``}
</div>
`;
}

protected override updated(changes: PropertyValues): void {
super.updated(changes);

if (changes.has('open')) {
if (this.open) {
this.addEventListener('keydown', this.handleKeydown);
} else {
this.removeEventListener('keydown', this.handleKeydown);
}
}
}
}