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(Empty State): add new bq-empty-state component #694

Merged
merged 5 commits into from
Dec 6, 2023
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
23 changes: 23 additions & 0 deletions packages/beeq/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { TButtonAppearance, TButtonSize, TButtonType, TButtonVariant } from "./c
import { TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types";
import { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types";
import { FloatingUIPlacement } from "./services/interfaces";
import { TEmptyStateSize } from "./components/empty-state/bq-empty-state.types";
import { TIconWeight } from "./components/icon/bq-icon.types";
import { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types";
import { TNotificationType } from "./components/notification/bq-notification.types";
Expand All @@ -33,6 +34,7 @@ export { TButtonAppearance, TButtonSize, TButtonType, TButtonVariant } from "./c
export { TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types";
export { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types";
export { FloatingUIPlacement } from "./services/interfaces";
export { TEmptyStateSize } from "./components/empty-state/bq-empty-state.types";
export { TIconWeight } from "./components/icon/bq-icon.types";
export { TInputType, TInputValidation, TInputValue } from "./components/input/bq-input.types";
export { TNotificationType } from "./components/notification/bq-notification.types";
Expand Down Expand Up @@ -367,6 +369,12 @@ export namespace Components {
*/
"strategy"?: 'fixed' | 'absolute';
}
interface BqEmptyState {
/**
* The size of the empty state component
*/
"size": TEmptyStateSize;
}
/**
* Icons are simplified images that graphically explain the meaning of an object on the screen.
*/
Expand Down Expand Up @@ -1350,6 +1358,12 @@ declare global {
prototype: HTMLBqDropdownElement;
new (): HTMLBqDropdownElement;
};
interface HTMLBqEmptyStateElement extends Components.BqEmptyState, HTMLStencilElement {
}
var HTMLBqEmptyStateElement: {
prototype: HTMLBqEmptyStateElement;
new (): HTMLBqEmptyStateElement;
};
interface HTMLBqIconElementEventMap {
"svgLoaded": any;
}
Expand Down Expand Up @@ -1725,6 +1739,7 @@ declare global {
"bq-dialog": HTMLBqDialogElement;
"bq-divider": HTMLBqDividerElement;
"bq-dropdown": HTMLBqDropdownElement;
"bq-empty-state": HTMLBqEmptyStateElement;
"bq-icon": HTMLBqIconElement;
"bq-input": HTMLBqInputElement;
"bq-notification": HTMLBqNotificationElement;
Expand Down Expand Up @@ -2118,6 +2133,12 @@ declare namespace LocalJSX {
*/
"strategy"?: 'fixed' | 'absolute';
}
interface BqEmptyState {
/**
* The size of the empty state component
*/
"size"?: TEmptyStateSize;
}
/**
* Icons are simplified images that graphically explain the meaning of an object on the screen.
*/
Expand Down Expand Up @@ -2966,6 +2987,7 @@ declare namespace LocalJSX {
"bq-dialog": BqDialog;
"bq-divider": BqDivider;
"bq-dropdown": BqDropdown;
"bq-empty-state": BqEmptyState;
"bq-icon": BqIcon;
"bq-input": BqInput;
"bq-notification": BqNotification;
Expand Down Expand Up @@ -3008,6 +3030,7 @@ declare module "@stencil/core" {
"bq-dialog": LocalJSX.BqDialog & JSXBase.HTMLAttributes<HTMLBqDialogElement>;
"bq-divider": LocalJSX.BqDivider & JSXBase.HTMLAttributes<HTMLBqDividerElement>;
"bq-dropdown": LocalJSX.BqDropdown & JSXBase.HTMLAttributes<HTMLBqDropdownElement>;
"bq-empty-state": LocalJSX.BqEmptyState & JSXBase.HTMLAttributes<HTMLBqEmptyStateElement>;
/**
* Icons are simplified images that graphically explain the meaning of an object on the screen.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { newE2EPage } from '@stencil/core/testing';

describe('bq-empty-state', () => {
it('should render', async () => {
const page = await newE2EPage({
html: '<bq-empty-state></bq-empty-state>',
});
const element = await page.find('bq-empty-state');

expect(element).toHaveClass('hydrated');
});

it('should have shadow root', async () => {
const page = await newE2EPage({
html: '<bq-empty-state></bq-empty-state>',
});
const element = await page.find('bq-empty-state');

expect(element.shadowRoot).not.toBeNull();
});

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

const element = await page.find('bq-empty-state >>> slot[name="body"]');

expect(element).not.toBeNull();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ArgTypes, Title, Subtitle } from '@storybook/addon-docs';

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

An Empty State is a UI component that is displayed when a user interacts with an application or system and there
is no data or content available to display. Empty States are common in applications that have dynamic or changing data,
or when the user is in a state of no activity or interaction.

<Subtitle>Usage</Subtitle>

- Use clear and concise language to explain the context of the empty state, so that users can understand the reason why there is no data or content available.
- Use visually appealing and positive design elements, such as illustrations, icons, or images, to keep users engaged and reduce frustration.
- Consider the use of humor or lightheartedness, if appropriate, to maintain a positive and inviting experience for users.
- Provide a clear and concise call-to-action that helps users navigate to other parts of the application or system, where they can find the data or content they need.
- Test the empty state with real users to ensure that it is effective in communicating the message and providing the guidance needed.

<Subtitle>👍 When to use</Subtitle>

- When to display a helpful message or guidance to users when there is no data or content available.
- When to provide a clear and concise way to inform users that there is no data or content available, so that they can understand the context and meaning of the empty state.
- When to provide an inviting and positive visual experience, to maintain user engagement and reduce frustration.
- When to include a call-to-action (CTA) that helps users navigate to other parts of the application or system, where they can find the data or content they need.

<Title>Properties</Title>

<ArgTypes of="bq-empty-state" />
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import type { Args, Meta, StoryObj } from '@storybook/web-components';
import { html } from 'lit-html';

import mdx from './bq-empty-state.mdx';
import { EMPTY_STATE_SIZE } from '../bq-empty-state.types';

const meta: Meta = {
title: 'Components/Empty state',
component: 'bq-empty-state',
parameters: {
docs: {
page: mdx,
},
},
argTypes: {
size: { control: 'select', options: [...EMPTY_STATE_SIZE] },
},
args: {
size: 'medium',
},
};
export default meta;

type Story = StoryObj;

const Template = (args: Args) => html` <bq-empty-state size=${args.size}> Title </bq-empty-state> `;

const TemplateWithBody = (args: Args) => html`
<div class="flex flex-row gap-20">
<bq-empty-state size=${args.size}>
Title
<span slot="body"> Description </span>
</bq-empty-state>
<bq-empty-state size=${args.size}>
Title <span slot="body"> Description <a class="bq-link" href="https://example.com">Link</a> </span>
</bq-empty-state>
</div>
`;

const TemplateWithCTA = (args: Args) => html`
<div class="flex flex-row gap-20">
<bq-empty-state size=${args.size}>
Title <span slot="body"> Description <a class="bq-link" href="https://example.com">Link</a> </span>
<div class="flex gap-xs" slot="footer">
<bq-button appearance="primary" size="small"> Button </bq-button>
</div>
</bq-empty-state>
<bq-empty-state size=${args.size}>
Title <span slot="body"> Description <a class="bq-link" href="https://example.com">Link</a> </span>
<div class="flex gap-xs" slot="footer">
<bq-button size="small" variant="ghost"> Button </bq-button>
</div>
</bq-empty-state>
<bq-empty-state size=${args.size}>
Title <span slot="body"> Description <a class="bq-link" href="https://example.com">Link</a> </span>
<div class="flex gap-xs" slot="footer">
<bq-button size="small" variant="ghost"> Button </bq-button>
<bq-button appearance="primary" size="small"> Button </bq-button>
</div>
</bq-empty-state>
</div>
`;

export const Default: Story = {
render: (args: Args) => html` <bq-empty-state size=${args.size}> Title </bq-empty-state> `,
};

export const WithBody: Story = {
render: (args: Args) => html`
<div class="flex flex-row gap-20">
<bq-empty-state size=${args.size}>
Title
<span slot="body"> Description </span>
</bq-empty-state>
<bq-empty-state size=${args.size}>
Title <span slot="body"> Description <a class="bq-link" href="https://example.com">Link</a> </span>
</bq-empty-state>
</div>
`,
};

export const WithCallToAction: Story = {
render: (args: Args) => html`
<div class="flex flex-row gap-20">
<bq-empty-state size=${args.size}>
Title <span slot="body"> Description <a class="bq-link" href="https://example.com">Link</a> </span>
<div class="flex gap-xs" slot="footer">
<bq-button appearance="primary" size="small"> Button </bq-button>
</div>
</bq-empty-state>
<bq-empty-state size=${args.size}>
Title <span slot="body"> Description <a class="bq-link" href="https://example.com">Link</a> </span>
<div class="flex gap-xs" slot="footer">
<bq-button size="small" variant="ghost"> Button </bq-button>
</div>
</bq-empty-state>
<bq-empty-state size=${args.size}>
Title <span slot="body"> Description <a class="bq-link" href="https://example.com">Link</a> </span>
<div class="flex gap-xs" slot="footer">
<bq-button size="small" variant="ghost"> Button </bq-button>
<bq-button appearance="primary" size="small"> Button </bq-button>
</div>
</bq-empty-state>
</div>
`,
};
Loading