Skip to content

Commit

Permalink
feat(Alert): add new bq-alert component (#675)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cata1989 authored Nov 30, 2023
1 parent 8947cc4 commit a146415
Show file tree
Hide file tree
Showing 11 changed files with 923 additions and 0 deletions.
103 changes: 103 additions & 0 deletions packages/beeq/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* It contains typing information for all components that exist in this project.
*/
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
import { TAlertType } from "./components/alert/bq-alert.types";
import { TAvatarShape, TAvatarSize } from "./components/avatar/bq-avatar.types";
import { TBadgeSize } from "./components/badge/bq-badge.types";
import { TButtonAppearance, TButtonSize, TButtonType, TButtonVariant } from "./components/button/bq-button.types";
Expand All @@ -25,6 +26,7 @@ import { TSwitchInnerLabel, TSwitchJustifyContent } from "./components/switch/bq
import { TTabSize } from "./components/tab/bq-tab.types";
import { TTextareaAutoCapitalize, TTextareaWrap } from "./components/textarea/bq-textarea.types";
import { TToastPlacement, TToastType } from "./components/toast/bq-toast.types";
export { TAlertType } from "./components/alert/bq-alert.types";
export { TAvatarShape, TAvatarSize } from "./components/avatar/bq-avatar.types";
export { TBadgeSize } from "./components/badge/bq-badge.types";
export { TButtonAppearance, TButtonSize, TButtonType, TButtonVariant } from "./components/button/bq-button.types";
Expand All @@ -46,6 +48,44 @@ export { TTabSize } from "./components/tab/bq-tab.types";
export { TTextareaAutoCapitalize, TTextareaWrap } from "./components/textarea/bq-textarea.types";
export { TToastPlacement, TToastType } from "./components/toast/bq-toast.types";
export namespace Components {
interface BqAlert {
/**
* If true, the alert will automatically hide after the specified amount of time
*/
"autoDismiss": boolean;
/**
* If true, the close button at the top right of the alert won't be shown
*/
"disableClose": boolean;
/**
* Method to be called to hide the alert component
*/
"hide": () => Promise<void>;
/**
* If true, the alert icon won't be shown
*/
"hideIcon": boolean;
/**
* If true, the alert will be shown
*/
"open": boolean;
/**
* Method to be called to show the alert component
*/
"show": () => Promise<void>;
/**
* If true, the alert component will remain fixed at the top of the page, occupying the full viewport
*/
"sticky": boolean;
/**
* The length of time, in milliseconds, after which the alert will close itself. Only valid if `autoDismiss="true"`
*/
"time": number;
/**
* Type of Alert
*/
"type": TAlertType;
}
interface BqAvatar {
/**
* Alternate text for the avatar image if the image cannot be displayed
Expand Down Expand Up @@ -1060,6 +1100,10 @@ export namespace Components {
"visible"?: boolean;
}
}
export interface BqAlertCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLBqAlertElement;
}
export interface BqBreadcrumbCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLBqBreadcrumbElement;
Expand Down Expand Up @@ -1153,6 +1197,24 @@ export interface BqToastCustomEvent<T> extends CustomEvent<T> {
target: HTMLBqToastElement;
}
declare global {
interface HTMLBqAlertElementEventMap {
"bqHide": any;
"bqShow": any;
}
interface HTMLBqAlertElement extends Components.BqAlert, HTMLStencilElement {
addEventListener<K extends keyof HTMLBqAlertElementEventMap>(type: K, listener: (this: HTMLBqAlertElement, ev: BqAlertCustomEvent<HTMLBqAlertElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof HTMLBqAlertElementEventMap>(type: K, listener: (this: HTMLBqAlertElement, ev: BqAlertCustomEvent<HTMLBqAlertElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
var HTMLBqAlertElement: {
prototype: HTMLBqAlertElement;
new (): HTMLBqAlertElement;
};
interface HTMLBqAvatarElement extends Components.BqAvatar, HTMLStencilElement {
}
var HTMLBqAvatarElement: {
Expand Down Expand Up @@ -1653,6 +1715,7 @@ declare global {
new (): HTMLBqTooltipElement;
};
interface HTMLElementTagNameMap {
"bq-alert": HTMLBqAlertElement;
"bq-avatar": HTMLBqAvatarElement;
"bq-badge": HTMLBqBadgeElement;
"bq-breadcrumb": HTMLBqBreadcrumbElement;
Expand Down Expand Up @@ -1688,6 +1751,44 @@ declare global {
}
}
declare namespace LocalJSX {
interface BqAlert {
/**
* If true, the alert will automatically hide after the specified amount of time
*/
"autoDismiss"?: boolean;
/**
* If true, the close button at the top right of the alert won't be shown
*/
"disableClose"?: boolean;
/**
* If true, the alert icon won't be shown
*/
"hideIcon"?: boolean;
/**
* Callback handler to be called when the notification is hidden
*/
"onBqHide"?: (event: BqAlertCustomEvent<any>) => void;
/**
* Callback handler to be called when the notification is shown
*/
"onBqShow"?: (event: BqAlertCustomEvent<any>) => void;
/**
* If true, the alert will be shown
*/
"open"?: boolean;
/**
* If true, the alert component will remain fixed at the top of the page, occupying the full viewport
*/
"sticky"?: boolean;
/**
* The length of time, in milliseconds, after which the alert will close itself. Only valid if `autoDismiss="true"`
*/
"time"?: number;
/**
* Type of Alert
*/
"type"?: TAlertType;
}
interface BqAvatar {
/**
* Alternate text for the avatar image if the image cannot be displayed
Expand Down Expand Up @@ -2855,6 +2956,7 @@ declare namespace LocalJSX {
"visible"?: boolean;
}
interface IntrinsicElements {
"bq-alert": BqAlert;
"bq-avatar": BqAvatar;
"bq-badge": BqBadge;
"bq-breadcrumb": BqBreadcrumb;
Expand Down Expand Up @@ -2893,6 +2995,7 @@ export { LocalJSX as JSX };
declare module "@stencil/core" {
export namespace JSX {
interface IntrinsicElements {
"bq-alert": LocalJSX.BqAlert & JSXBase.HTMLAttributes<HTMLBqAlertElement>;
"bq-avatar": LocalJSX.BqAvatar & JSXBase.HTMLAttributes<HTMLBqAvatarElement>;
"bq-badge": LocalJSX.BqBadge & JSXBase.HTMLAttributes<HTMLBqBadgeElement>;
"bq-breadcrumb": LocalJSX.BqBreadcrumb & JSXBase.HTMLAttributes<HTMLBqBreadcrumbElement>;
Expand Down
135 changes: 135 additions & 0 deletions packages/beeq/src/components/alert/__tests__/bq-alert.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { newE2EPage } from '@stencil/core/testing';

describe('bq-alert', () => {
it('should render', async () => {
const page = await newE2EPage({
html: `<bq-alert></bq-alert>`,
});

const element = await page.find('bq-alert');
expect(element).toHaveClass('hydrated');
});

it('should have shadow root', async () => {
const page = await newE2EPage({
html: `<bq-alert></bq-alert>`,
});

const element = await page.find('bq-alert');
expect(element.shadowRoot).not.toBeNull();
});

it('should render as hidden', async () => {
const page = await newE2EPage({
html: `<bq-alert></bq-alert>`,
});

const element = await page.find('bq-alert');
expect(element).toEqualAttribute('aria-hidden', 'true');
expect(element).toHaveClass('is-hidden');
});

it('should render as hidden with `open="false"`', async () => {
const page = await newE2EPage({
html: `<bq-alert open="false"></bq-alert>`,
});

const element = await page.find('bq-alert');
expect(element).toEqualAttribute('aria-hidden', 'true');
expect(element).toHaveClass('is-hidden');
});

it('should render as open', async () => {
const page = await newE2EPage({
html: `<bq-alert open></bq-alert>`,
});

const element = await page.find('bq-alert');
expect(element).not.toEqualAttribute('aria-hidden', 'true');
expect(element).not.toHaveClass('is-hidden');
});

it('should render as open with `open="true"`', async () => {
const page = await newE2EPage({
html: `<bq-alert open="true"></bq-alert>`,
});

const element = await page.find('bq-alert');
expect(element).not.toEqualAttribute('aria-hidden', 'true');
expect(element).not.toHaveClass('is-hidden');
});

it('should render basic alert', async () => {
const page = await newE2EPage({
html: `
<bq-alert>
Alert title
<span slot="body">You have a new alert message</span>
</bq-alert>
`,
});

const description = await page.find('bq-alert >>> slot[name="body"]');
expect(description).not.toBeNull();
});

it('should show alert with icon', async () => {
const page = await newE2EPage({
html: `<bq-alert type="info">Alert title</bq-alert>`,
});

const iconHolder = await page.find('bq-alert >>> [part="icon-outline"]');
expect(iconHolder).not.toBeNull();
});

it('should show alert with close button', async () => {
const page = await newE2EPage({
html: `<bq-alert type="info">Alert title</bq-alert>`,
});

const iconHolder = await page.find('bq-alert >>> [part="btn-close"]');
expect(iconHolder).not.toBeNull();
});

it('should show alert footer', async () => {
const page = await newE2EPage({
html: `
<bq-alert>
Alert title
<div slot="footer">
<bq-button appearance="primary" type="button" variant="standard">Button</bq-button>
<bq-button appearance="secondary" variant="standard">Button</bq-button>
</div>
</bq-alert>
`,
});

const footerSlot = await page.find('bq-alert >>> slot[name="footer"]');
expect(footerSlot).not.toBeNull();
});

it('should call methods', async () => {
const page = await newE2EPage({
html: `
<bq-alert>
Alert title
<span slot="body">You have a new alert message</span>
</bq-alert>
`,
});

const element = await page.find('bq-alert');

await element.callMethod('show');
await page.waitForChanges();

expect(element).toEqualAttribute('aria-hidden', 'false');
expect(element).toEqualAttribute('hidden', 'false');

await element.callMethod('hide');
await page.waitForChanges();

expect(element).toEqualAttribute('aria-hidden', 'true');
expect(element).toEqualAttribute('hidden', 'true');
});
});
29 changes: 29 additions & 0 deletions packages/beeq/src/components/alert/_storybook/bq-alert.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ArgTypes, Title, Subtitle } from '@storybook/addon-docs';

<div className="bq-doc__wrapper" data-theme="light">
<div className="bq-doc__container">
<Title>Alert</Title>

The Alert is a user interface component used to convey important information to the user in a clear and concise manner.
It can be used to notify users of success, failure, warning, or any other type of information that needs to be brought to their attention.

<Subtitle>Usage</Subtitle>

- Use alerts to inform users about important events or actions such as successful login, account creation, and password reset.
- Use alerts to inform users about errors or warnings such as incorrect login credentials, network errors, or session timeouts.
- Use alerts to provide users with feedback about their actions such as a successful submission of a form or a message that a file has been uploaded successfully.
- Use alerts to inform users about system status such as maintenance downtime or system upgrades.

<Subtitle>👍 When to use</Subtitle>

- When to communicate critical updates such as important software patches, system maintenance, or urgent changes affecting the user experience.
- When to to provide real-time feedback on authentication status, including successful logins, failed login attempts, or session expirations.
- When to enhance user experience by utilizing the Alert component to confirm successful data submissions or to notify users about any errors encountered during the submission process.
- When to keep users informed about any changes in their permissions or access levels by leveraging the Alert component to deliver relevant and timely notifications.
- When to improve user engagement and timely actions by using the Alert component to remind users of upcoming events, deadlines, or other time-sensitive tasks.

<Title>Properties</Title>

<ArgTypes of="bq-alert" />
</div>
</div>
Loading

0 comments on commit a146415

Please sign in to comment.