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(Drawer): add new bq-drawer component #918

Merged
merged 39 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
8b0e8b5
feat(Drawer): generate basic structure for bq-drawer component
Cata1989 Mar 6, 2024
54bfe2d
feat(Drawer): implement open/close events and establish fundamental c…
Cata1989 Mar 7, 2024
3165b11
feat(Drawer): add icon and footer at bq-drawer and some style
Cata1989 Mar 8, 2024
fb8b75a
feat(Drawer): refactor css style and add placement prop
Cata1989 Mar 11, 2024
44b96b3
feat(Drawer): add let/right placement transition
Cata1989 Mar 11, 2024
0f39631
feat(Drawer): rename hide/show events
Cata1989 Mar 12, 2024
dc8839a
feat(Drawer): remove improper handling of hide event
Cata1989 Mar 12, 2024
4abc205
feat(Drawer): add disable-close-click-outside prop to prevent closing…
Cata1989 Mar 12, 2024
b6c735a
feat(Drawer): add enableBackdrop and disableCloseEscKeydown
Cata1989 Mar 12, 2024
fcdceb2
feat(Drawer): remove unnecessary cancel event and add bg for backdrop
Cata1989 Mar 12, 2024
d86ac7a
feat(Drawer): refactor drawer transform logic
Cata1989 Mar 13, 2024
aaac7d7
feat(Drawer): add drawer width variable and refactor css
Cata1989 Mar 13, 2024
1e1ed06
feat(Drawer): add extra space
Cata1989 Mar 13, 2024
0b11c80
feat(Drawer): add some basic unit tests
Cata1989 Mar 13, 2024
07b2b6a
feat(Drawer): add part description
Cata1989 Mar 13, 2024
b6dfea1
feat(Drawer): update mdx file with component description
Cata1989 Mar 13, 2024
c44586c
feat(Drawer): add e2e test for footer slot
Cata1989 Mar 13, 2024
bf5ea86
feat(Drawer): refactor getMoveTranslate function
Cata1989 Mar 13, 2024
d87e687
feat(Drawer): resolve left comments
Cata1989 Mar 14, 2024
76e87a3
feat(Drawer): refact css structure and optimize component
Cata1989 Mar 14, 2024
2f1d70f
feat(Drawer): remove dialog role
Cata1989 Mar 14, 2024
1ad7e06
feat(Drawer): add overflow styles to Storybook preview and component …
Cata1989 Mar 15, 2024
a3c4209
feat(Drawer): add presentation role
Cata1989 Mar 15, 2024
4555242
refactor: replace enter/leave with internal transition util
dgonzalezr Mar 18, 2024
3d9100c
refactor: use object map instead of switch statement
dgonzalezr Mar 18, 2024
f0ddeb3
refactor: use a wrapper Div and move most of Tailwind utility to JSX
dgonzalezr Mar 18, 2024
3bd94d8
refactor: show and hide handlers to use early return
dgonzalezr Mar 18, 2024
2142f61
refactor: set host visibility before and after the transitions take p…
dgonzalezr Mar 18, 2024
697061f
fix: check for Prop values on component will load
dgonzalezr Mar 18, 2024
3a32620
refactor: open() @watch handler to use async/await
dgonzalezr Mar 18, 2024
680a316
refactor: keyboard and mouse event listener to call hide() method ins…
dgonzalezr Mar 18, 2024
f7a0316
fix: shadow DOM parts documentation
dgonzalezr Mar 18, 2024
838785a
refactor: remove useless rules
dgonzalezr Mar 18, 2024
49ebdf8
docs: update Storybook example
dgonzalezr Mar 18, 2024
24251d8
docs: autogenerated readme file
dgonzalezr Mar 18, 2024
c4db6e4
revert: use a wrapper Div and keep the use of Host
dgonzalezr Mar 18, 2024
849e930
fix: used `position: fixed` instead to avoid horizontal scroll
dgonzalezr Mar 18, 2024
4785c7a
test: fix e2e tests
dgonzalezr Mar 18, 2024
e83bb10
docs: add more Storybook examples
dgonzalezr Mar 18, 2024
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
2 changes: 1 addition & 1 deletion packages/beeq/.storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const withThemeProvider: DecoratorFunction<WebComponentsRenderer, { [x: string]:
globals: { theme, mode },
} = context;
const body = document.querySelector('body.sb-show-main');
if (!body) return storyFn();
if (!(body instanceof HTMLElement)) return storyFn();

body.setAttribute('bq-theme', (theme || 'BEEQ').toLowerCase());
body.setAttribute('bq-mode', (mode || 'Light').toLowerCase());
Expand Down
97 changes: 97 additions & 0 deletions packages/beeq/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButt
import { TCardBorderRadius, TCardType } from "./components/card/bq-card.types";
import { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types";
import { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types";
import { TDrawerPlacement } from "./components/drawer/bq-drawer.types";
import { FloatingUIPlacement } from "./services/interfaces";
import { TEmptyStateSize } from "./components/empty-state/bq-empty-state.types";
import { TIconWeight } from "./components/icon/bq-icon.types";
Expand All @@ -38,6 +39,7 @@ export { TButtonAppearance, TButtonBorderRadius, TButtonSize, TButtonType, TButt
export { TCardBorderRadius, TCardType } from "./components/card/bq-card.types";
export { TDialogBorderRadius, TDialogFooterAppearance, TDialogSize } from "./components/dialog/bq-dialog.types";
export { TDividerOrientation, TDividerStrokeLinecap, TDividerTitleAlignment } from "./components/divider/bq-divider.types";
export { TDrawerPlacement } from "./components/drawer/bq-drawer.types";
export { FloatingUIPlacement } from "./services/interfaces";
export { TEmptyStateSize } from "./components/empty-state/bq-empty-state.types";
export { TIconWeight } from "./components/icon/bq-icon.types";
Expand Down Expand Up @@ -399,6 +401,36 @@ export namespace Components {
*/
"titleAlignment"?: TDividerTitleAlignment;
}
interface BqDrawer {
/**
* If true, the drawer will not close when clicking outside the panel
*/
"closeOnClickOutside": boolean;
/**
* If true, the dialog will not close when the [Esc] key is pressed
*/
"closeOnEsc": boolean;
/**
* If true, the backdrop overlay will be shown when the drawer opens
*/
"enableBackdrop": boolean;
/**
* Method to be called to hide the drawer component
*/
"hide": () => Promise<void>;
/**
* If true, the drawer component will be shown
*/
"open": boolean;
/**
* Defines the position of the drawer
*/
"placement": TDrawerPlacement;
/**
* Method to be called to show the drawer component
*/
"show": () => Promise<void>;
}
interface BqDropdown {
/**
* If true, the dropdown panel will be visible and won't be shown.
Expand Down Expand Up @@ -1272,6 +1304,10 @@ export interface BqDialogCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLBqDialogElement;
}
export interface BqDrawerCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLBqDrawerElement;
}
export interface BqDropdownCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLBqDropdownElement;
Expand Down Expand Up @@ -1518,6 +1554,26 @@ declare global {
prototype: HTMLBqDividerElement;
new (): HTMLBqDividerElement;
};
interface HTMLBqDrawerElementEventMap {
"bqClose": any;
"bqOpen": any;
"bqAfterOpen": any;
"bqAfterClose": any;
}
interface HTMLBqDrawerElement extends Components.BqDrawer, HTMLStencilElement {
addEventListener<K extends keyof HTMLBqDrawerElementEventMap>(type: K, listener: (this: HTMLBqDrawerElement, ev: BqDrawerCustomEvent<HTMLBqDrawerElementEventMap[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 HTMLBqDrawerElementEventMap>(type: K, listener: (this: HTMLBqDrawerElement, ev: BqDrawerCustomEvent<HTMLBqDrawerElementEventMap[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 HTMLBqDrawerElement: {
prototype: HTMLBqDrawerElement;
new (): HTMLBqDrawerElement;
};
interface HTMLBqDropdownElementEventMap {
"bqOpen": { open: boolean };
}
Expand Down Expand Up @@ -1941,6 +1997,7 @@ declare global {
"bq-checkbox": HTMLBqCheckboxElement;
"bq-dialog": HTMLBqDialogElement;
"bq-divider": HTMLBqDividerElement;
"bq-drawer": HTMLBqDrawerElement;
"bq-dropdown": HTMLBqDropdownElement;
"bq-empty-state": HTMLBqEmptyStateElement;
"bq-icon": HTMLBqIconElement;
Expand Down Expand Up @@ -2377,6 +2434,44 @@ declare namespace LocalJSX {
*/
"titleAlignment"?: TDividerTitleAlignment;
}
interface BqDrawer {
/**
* If true, the drawer will not close when clicking outside the panel
*/
"closeOnClickOutside"?: boolean;
/**
* If true, the dialog will not close when the [Esc] key is pressed
*/
"closeOnEsc"?: boolean;
/**
* If true, the backdrop overlay will be shown when the drawer opens
*/
"enableBackdrop"?: boolean;
/**
* Callback handler to be called after the drawer has been closed
*/
"onBqAfterClose"?: (event: BqDrawerCustomEvent<any>) => void;
/**
* Callback handler to be called after the drawer has been opened
*/
"onBqAfterOpen"?: (event: BqDrawerCustomEvent<any>) => void;
/**
* Callback handler to be called when the drawer is closed
*/
"onBqClose"?: (event: BqDrawerCustomEvent<any>) => void;
/**
* Callback handler to be called when the drawer is opened
*/
"onBqOpen"?: (event: BqDrawerCustomEvent<any>) => void;
/**
* If true, the drawer component will be shown
*/
"open"?: boolean;
/**
* Defines the position of the drawer
*/
"placement"?: TDrawerPlacement;
}
interface BqDropdown {
/**
* If true, the dropdown panel will be visible and won't be shown.
Expand Down Expand Up @@ -3357,6 +3452,7 @@ declare namespace LocalJSX {
"bq-checkbox": BqCheckbox;
"bq-dialog": BqDialog;
"bq-divider": BqDivider;
"bq-drawer": BqDrawer;
"bq-dropdown": BqDropdown;
"bq-empty-state": BqEmptyState;
"bq-icon": BqIcon;
Expand Down Expand Up @@ -3404,6 +3500,7 @@ declare module "@stencil/core" {
"bq-checkbox": LocalJSX.BqCheckbox & JSXBase.HTMLAttributes<HTMLBqCheckboxElement>;
"bq-dialog": LocalJSX.BqDialog & JSXBase.HTMLAttributes<HTMLBqDialogElement>;
"bq-divider": LocalJSX.BqDivider & JSXBase.HTMLAttributes<HTMLBqDividerElement>;
"bq-drawer": LocalJSX.BqDrawer & JSXBase.HTMLAttributes<HTMLBqDrawerElement>;
"bq-dropdown": LocalJSX.BqDropdown & JSXBase.HTMLAttributes<HTMLBqDropdownElement>;
"bq-empty-state": LocalJSX.BqEmptyState & JSXBase.HTMLAttributes<HTMLBqEmptyStateElement>;
/**
Expand Down
2 changes: 1 addition & 1 deletion packages/beeq/src/components/alert/scss/bq-alert.scss
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
}

/**
* Tweak the close bq-buton styles so it remain small wihout extra padding
* Tweak the close bq-button styles so it remain small without extra padding
*/
.bq-alert__close::part(button) {
@apply h-fit rounded-s border-0 p-0;
Expand Down
2 changes: 2 additions & 0 deletions packages/beeq/src/components/button/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Buttons are designed for users to take action on a page or a screen.

- [bq-alert](../alert)
- [bq-dialog](../dialog)
- [bq-drawer](../drawer)
- [bq-input](../input)
- [bq-notification](../notification)
- [bq-select](../select)
Expand All @@ -67,6 +68,7 @@ graph TD;
bq-button --> bq-icon
bq-alert --> bq-button
bq-dialog --> bq-button
bq-drawer --> bq-button
bq-input --> bq-button
bq-notification --> bq-button
bq-select --> bq-button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ArgTypes, Title, Subtitle } from '@storybook/addon-docs';
<div className="bq-doc__container" >
<Title>Dialog</Title>

Description A Dialog is a UI component used to display additional content or prompt a user for action.
A Dialog is a UI component used to display additional content or prompt a user for action.
It provides a way to display additional information, options, or controls in a separate, non-obstructive interface element.

<Subtitle>Usage</Subtitle>
Expand Down
2 changes: 2 additions & 0 deletions packages/beeq/src/components/divider/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@

### Used by

- [bq-drawer](../drawer)
- [bq-steps](../steps)

### Graph
```mermaid
graph TD;
bq-drawer --> bq-divider
bq-steps --> bq-divider
style bq-divider fill:#f9f,stroke:#333,stroke-width:4px
```
Expand Down
144 changes: 144 additions & 0 deletions packages/beeq/src/components/drawer/__tests__/bq-drawer.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { newE2EPage } from '@stencil/core/testing';

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

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

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

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

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

const element = await page.find('bq-drawer >>> [part="panel"]');
expect(element).toEqualAttribute('aria-hidden', 'true');
});

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

const element = await page.find('bq-drawer >>> [part="panel"]');
expect(element).toEqualAttribute('aria-hidden', 'true');
});

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

const element = await page.find('bq-drawer >>> [part="panel"]');
expect(element).toEqualAttribute('aria-hidden', 'false');
expect(element).not.toHaveClass('hidden');
});

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

const element = await page.find('bq-drawer >>> [part="panel"]');
expect(element).toEqualAttribute('aria-hidden', 'false');
expect(element).not.toHaveClass('hidden');
});

it('should display drawer title', async () => {
const page = await newE2EPage({
html: `
<bq-drawer>
<div slot="title">Drawer Title</div>
</bq-drawer>
`,
});

const element = await page.find('bq-drawer');
expect(element).toEqualText('Drawer Title');
});

it('should render basic body drawer slot', async () => {
const page = await newE2EPage({
html: `
<bq-drawer>
<div slot>Slot</div>
</bq-drawer>
`,
});

const description = await page.find('bq-drawer >>> slot');
expect(description).not.toBeNull();
});

it('should render footer drawer slot', async () => {
const page = await newE2EPage({
html: `
<bq-drawer>
<div slot="footer">Footer slot</div>
</bq-drawer>
`,
});

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

it('should call `show` method', async () => {
const page = await newE2EPage({
html: `
<bq-drawer>
<div slot="title">Drawer Title</div>
</bq-drawer>
`,
});

const closedDrawer = await page.find('bq-drawer >>> [part="panel"]');
expect(closedDrawer.getAttribute('aria-hidden')).toBe('true');
expect(closedDrawer).toHaveAttribute('hidden');

await page.$eval('bq-drawer', async (elem: HTMLBqDrawerElement) => {
await elem.show();
});
await page.waitForChanges();

const openDrawer = await page.find('bq-drawer >>> [part="panel"]');
expect(openDrawer.getAttribute('aria-hidden')).toBe('false');
expect(openDrawer).not.toHaveAttribute('hidden');
});

it('should call `hide` method', async () => {
const page = await newE2EPage({
html: `
<bq-drawer open>
<div slot="title">Drawer Title</div>
</bq-drawer>
`,
});

const openDrawer = await page.find('bq-drawer >>> [part="panel"]');
expect(openDrawer.getAttribute('aria-hidden')).toBe('false');
expect(openDrawer).not.toHaveAttribute('hidden');

await page.$eval('bq-drawer', async (elem: HTMLBqDrawerElement) => {
await elem.hide();
});
await page.waitForChanges();

const closedDrawer = await page.find('bq-drawer >>> [part="panel"]');
expect(closedDrawer.getAttribute('aria-hidden')).toBe('true');
expect(closedDrawer).toHaveAttribute('hidden');
});
});
30 changes: 30 additions & 0 deletions packages/beeq/src/components/drawer/_storybook/bq-drawer.mdx
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>Drawer</Title>

A Drawer is a UI component that provides a sliding panel interface commonly used for navigation or presenting
additional content without taking up significant screen space.

<Subtitle>Usage</Subtitle>

- Navigation: Drawers are commonly used for housing navigation menus or sidebar menus. They can be toggled open
and closed to provide easy access to navigation links.
- Additional content: This component can also be used to display additional content or options that are not always visible on the screen.
This allows to access exatra functionality without cluttering the main interface.

<Subtitle>👍 When to use</Subtitle>

Utilize the Drawer component for various scenarios such as sidebar navigation, user preferences display, and mobile menu implementation,
offering compact access to application sections, settings, and navigation options.

- Limited screen space: When screen real estate is limited, such as on mobile devices or smaller viewports, drawers can provide a compact way to present additional content.
- Contextual information: Use drawers to display contextual information or actions related to the current screen or user interaction.
- Multi-level Navigation: Drawers are suitable for multi-level navigation structures, where sub-menus or nested content can be displayed hierarchically.

<Title>Properties</Title>

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