Skip to content

Commit

Permalink
feat(Progress): add new bq-progress component (#946)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cata1989 authored Mar 28, 2024
1 parent 9d590d7 commit a99d737
Show file tree
Hide file tree
Showing 13 changed files with 599 additions and 3 deletions.
71 changes: 71 additions & 0 deletions packages/beeq/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ 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 { TNotificationBorderRadius, TNotificationType } from "./components/notification/bq-notification.types";
import { TProgressBorderShape, TProgressThickness, TProgressType } from "./components/progress/bq-progress.types";
import { TRadioGroupOrientation } from "./components/radio-group/bq-radio-group.types";
import { TSideMenuAppearance, TSideMenuSize } from "./components/side-menu/bq-side-menu.types";
import { TSliderType } from "./components/slider/bq-slider.types";
Expand All @@ -45,6 +46,7 @@ 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 { TNotificationBorderRadius, TNotificationType } from "./components/notification/bq-notification.types";
export { TProgressBorderShape, TProgressThickness, TProgressType } from "./components/progress/bq-progress.types";
export { TRadioGroupOrientation } from "./components/radio-group/bq-radio-group.types";
export { TSideMenuAppearance, TSideMenuSize } from "./components/side-menu/bq-side-menu.types";
export { TSliderType } from "./components/slider/bq-slider.types";
Expand Down Expand Up @@ -689,6 +691,36 @@ export namespace Components {
*/
"strategy"?: 'fixed' | 'absolute';
}
interface BqProgress {
/**
* It will set the border style of the progress bar
*/
"borderShape": TProgressBorderShape;
/**
* If `true`, a tooltip will be shown displaying the progress value
*/
"enableTooltip": boolean;
/**
* If `true` the indeterminate state of progress bar is enabled
*/
"indeterminate": boolean;
/**
* If `true`, a label text showing the value (in percentage) will be shown
*/
"label": boolean;
/**
* Progress bar thickness
*/
"thickness": TProgressThickness;
/**
* Progress type
*/
"type": TProgressType;
/**
* A number representing the current value of the progress bar
*/
"value": number;
}
interface BqRadio {
/**
* If true radio displays background on hover
Expand Down Expand Up @@ -1715,6 +1747,12 @@ declare global {
prototype: HTMLBqPanelElement;
new (): HTMLBqPanelElement;
};
interface HTMLBqProgressElement extends Components.BqProgress, HTMLStencilElement {
}
var HTMLBqProgressElement: {
prototype: HTMLBqProgressElement;
new (): HTMLBqProgressElement;
};
interface HTMLBqRadioElementEventMap {
"bqClick": HTMLBqRadioElement;
"bqFocus": HTMLBqRadioElement;
Expand Down Expand Up @@ -2015,6 +2053,7 @@ declare global {
"bq-option-group": HTMLBqOptionGroupElement;
"bq-option-list": HTMLBqOptionListElement;
"bq-panel": HTMLBqPanelElement;
"bq-progress": HTMLBqProgressElement;
"bq-radio": HTMLBqRadioElement;
"bq-radio-group": HTMLBqRadioGroupElement;
"bq-select": HTMLBqSelectElement;
Expand Down Expand Up @@ -2803,6 +2842,36 @@ declare namespace LocalJSX {
*/
"strategy"?: 'fixed' | 'absolute';
}
interface BqProgress {
/**
* It will set the border style of the progress bar
*/
"borderShape"?: TProgressBorderShape;
/**
* If `true`, a tooltip will be shown displaying the progress value
*/
"enableTooltip"?: boolean;
/**
* If `true` the indeterminate state of progress bar is enabled
*/
"indeterminate"?: boolean;
/**
* If `true`, a label text showing the value (in percentage) will be shown
*/
"label"?: boolean;
/**
* Progress bar thickness
*/
"thickness"?: TProgressThickness;
/**
* Progress type
*/
"type"?: TProgressType;
/**
* A number representing the current value of the progress bar
*/
"value"?: number;
}
interface BqRadio {
/**
* If true radio displays background on hover
Expand Down Expand Up @@ -3487,6 +3556,7 @@ declare namespace LocalJSX {
"bq-option-group": BqOptionGroup;
"bq-option-list": BqOptionList;
"bq-panel": BqPanel;
"bq-progress": BqProgress;
"bq-radio": BqRadio;
"bq-radio-group": BqRadioGroup;
"bq-select": BqSelect;
Expand Down Expand Up @@ -3538,6 +3608,7 @@ declare module "@stencil/core" {
"bq-option-group": LocalJSX.BqOptionGroup & JSXBase.HTMLAttributes<HTMLBqOptionGroupElement>;
"bq-option-list": LocalJSX.BqOptionList & JSXBase.HTMLAttributes<HTMLBqOptionListElement>;
"bq-panel": LocalJSX.BqPanel & JSXBase.HTMLAttributes<HTMLBqPanelElement>;
"bq-progress": LocalJSX.BqProgress & JSXBase.HTMLAttributes<HTMLBqProgressElement>;
"bq-radio": LocalJSX.BqRadio & JSXBase.HTMLAttributes<HTMLBqRadioElement>;
"bq-radio-group": LocalJSX.BqRadioGroup & JSXBase.HTMLAttributes<HTMLBqRadioGroupElement>;
"bq-select": LocalJSX.BqSelect & JSXBase.HTMLAttributes<HTMLBqSelectElement>;
Expand Down
126 changes: 126 additions & 0 deletions packages/beeq/src/components/progress/__tests__/bq-progress.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { newE2EPage } from '@stencil/core/testing';

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

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

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

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

it('should render the progress bar with label', async () => {
const value = 60;
const page = await newE2EPage({
html: `<bq-progress value="${value}" label></progress>`,
});

const element = await page.find('bq-progress >>> [part="label"] span');
expect(element).not.toBeNull();
expect(element.textContent).toEqual(`${value}%`);
});

it('should render the progress bar without label', async () => {
const page = await newE2EPage({
html: '<bq-progress value="60" label="false"></progress>',
});

const element = await page.find('bq-progress >>> [part="label"]');
expect(element).toHaveClass('hidden');
});

it('should render the progress bar with tooltip', async () => {
const value = 60;
const page = await newE2EPage({
html: `<bq-progress value="${value}" enable-tooltip></progress>`,
});

const element = await page.find('bq-progress >>> bq-tooltip');
expect(element).not.toBeNull();
expect(element.innerText).toEqual(`${value}`);
});

it('should render the progress bar without tooltip', async () => {
const page = await newE2EPage({
html: '<bq-progress value="60" enable-tooltip="false"></progress>',
});

const element = await page.find('bq-progress >>> bq-tooltip');
expect(element).toBeNull();
});

it('should render the progress bar with error type', async () => {
const page = await newE2EPage({
html: '<bq-progress value="60" type="error"></progress>',
});

const progressElem = await page.find('bq-progress >>> [part="progress-bar"]');
expect(progressElem).toHaveClass('progress-bar__error');

const labelElem = await page.find('bq-progress >>> [part="label"]');
expect(labelElem).toHaveClass('text-ui-danger');

const uiDangerToken = await page.evaluate(() =>
getComputedStyle(document.documentElement).getPropertyValue('--bq-ui--danger'),
);
const indicatorColor = await page.$eval('bq-progress', (elm: any) =>
getComputedStyle(elm.shadowRoot.querySelector('[part="progress-bar"]')).getPropertyValue(
'--bq-progress-bar--indicatorColor',
),
);
expect(indicatorColor).toEqual(uiDangerToken);
});

it('should render the progress bar with large thickness', async () => {
const page = await newE2EPage({
html: '<bq-progress value="60" thickness="large"></progress>',
});

const uiLargeThicknessToken = await page.evaluate(() =>
getComputedStyle(document.documentElement).getPropertyValue('--bq-spacing-xs'),
);
const indicatorThickness = await page.$eval('bq-progress', (elm: any) =>
getComputedStyle(elm.shadowRoot.querySelector('[part="progress-bar"]')).getPropertyValue(
'--bq-progress-bar--height',
),
);
expect(indicatorThickness).toEqual(uiLargeThicknessToken);
});

it('should render the progress bar in indeterminate mode', async () => {
const page = await newE2EPage({
html: '<bq-progress value="60" indeterminate></progress>',
});

const element = await page.find('bq-progress >>> [part="progress"]');
expect(element).not.toHaveAttribute('value');
});

it('should render the progress bar with border shape as rounded', async () => {
const page = await newE2EPage({
html: '<bq-progress value="60" border-shape="rounded"></progress>',
});

const progressElem = await page.find('bq-progress >>> [part="progress-bar"]');
expect(progressElem).toHaveClass('progress-bar__border-shape');
});

it('should render the progress bar with border shape as square', async () => {
const page = await newE2EPage({
html: '<bq-progress value="60" border-shape="square"></progress>',
});

const progressElem = await page.find('bq-progress >>> [part="progress-bar"]');
expect(progressElem).not.toHaveClass('progress-bar__border-shape');
});
});
28 changes: 28 additions & 0 deletions packages/beeq/src/components/progress/_storybook/bq-progress.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ArgTypes, Title, Subtitle } from '@storybook/addon-docs';

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

The progress bar is a user interface component that visually represents the completion status of a task or process. It typically consists of a horizontal bar
that fills up gradually to indicate the progress of the task, often accompanied by textual or graphical indicators such as percentages or toolip labels.

<Subtitle>Usage</Subtitle>

- Use the progress bar to visually track the completion status of a task, operation, or process.
- Use the progress bar to provide users with feedback on the progress of actions, such as file uploads, form submissions, or loading processes.
- Use the progress bar to improve the user experience by offering a clear indication of the current status and remaining duration of ongoing operations.
- Use the progress bar to manage user expectations by displaying a progress bar actions that require some time to complete, reducing uncertainty and frustration.

<Subtitle>👍 When to use</Subtitle>

- When to employ communication for tasks or operations that take a significant amount of time to complete, ensuring users stay informed about the ongoing process.
- When to implement communication for asynchronous actions, like data fetching, API calls, or background processes, to signify activity and provide users with confidence in system responsiveness.
- When to offer communication on user interactions, such as button clicks, form submissions, or page transitions, by employing methods like progress bars to indicate ongoing actions.
- When to apply communication for dynamic updates, where progress is updated in real-time based on changing conditions or user inputs, enhancing clarity and responsiveness.

<Title>Properties</Title>

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

import mdx from './bq-progress.mdx';
import { PROGRESS_BORDER_SHAPE, PROGRESS_THICKNESS, PROGRESS_TYPE } from '../bq-progress.types';

const meta: Meta = {
title: 'Components/Progress',
component: 'bq-progress',
parameters: {
docs: {
page: mdx,
},
},
argTypes: {
value: { control: 'number' },
indeterminate: { control: 'boolean' },
thickness: { control: 'select', options: [...PROGRESS_THICKNESS] },
type: { control: 'select', options: [...PROGRESS_TYPE] },
'border-shape': { control: 'select', options: [...PROGRESS_BORDER_SHAPE] },
label: { control: 'boolean' },
'enable-tooltip': { control: 'boolean' },
},
args: {
value: 0,
indeterminate: false,
thickness: 'medium',
type: 'default',
'border-shape': 'rounded',
label: false,
'enable-tooltip': false,
},
};
export default meta;

type Story = StoryObj;

const Template = (args: Args) => html`
<div class="w-64">
<bq-progress
value=${args.value}
indeterminate=${args.indeterminate}
thickness=${args.thickness}
type=${args.type}
border-shape=${args['border-shape']}
?label=${args.label}
?enable-tooltip=${args['enable-tooltip']}
></bq-progress>
</div>
`;

export const Default: Story = {
render: Template,
args: {
value: 10,
},
};

export const LargeThickness: Story = {
render: Template,
args: {
value: 20,
thickness: 'large',
},
};

export const ErrorState: Story = {
name: 'Error',
render: Template,
args: {
value: 40,
type: 'error',
},
};

export const BorderShape: Story = {
render: Template,
args: {
value: 80,
'border-shape': 'square',
},
};

export const WithLabel: Story = {
render: Template,
args: {
value: 60,
label: true,
},
};

export const WithTooltip: Story = {
render: Template,
args: {
value: 80,
'enable-tooltip': true,
},
};
Loading

0 comments on commit a99d737

Please sign in to comment.