diff --git a/packages/beeq/src/components.d.ts b/packages/beeq/src/components.d.ts index 204d7beb3..d1c4348dc 100644 --- a/packages/beeq/src/components.d.ts +++ b/packages/beeq/src/components.d.ts @@ -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"; @@ -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"; @@ -408,6 +410,7 @@ export namespace Components { * If true, the drawer component will be shown */ "open": boolean; + "placement"?: TDrawerPlacement; /** * Method to be called to show the notification component */ @@ -2437,6 +2440,7 @@ declare namespace LocalJSX { * If true, the drawer component will be shown */ "open"?: boolean; + "placement"?: TDrawerPlacement; } interface BqDropdown { /** diff --git a/packages/beeq/src/components/drawer/_storybook/bq-drawer.stories.tsx b/packages/beeq/src/components/drawer/_storybook/bq-drawer.stories.tsx index 802ea19a1..8dff2434b 100644 --- a/packages/beeq/src/components/drawer/_storybook/bq-drawer.stories.tsx +++ b/packages/beeq/src/components/drawer/_storybook/bq-drawer.stories.tsx @@ -2,6 +2,7 @@ import type { Args, Meta, StoryObj } from '@storybook/web-components'; import { html } from 'lit-html'; import mdx from './bq-drawer.mdx'; +import { DRAWER_PLACEMENT } from '../bq-drawer.types'; const meta: Meta = { title: 'Components/Drawer', @@ -13,6 +14,7 @@ const meta: Meta = { }, argTypes: { open: { control: 'boolean' }, + placement: { control: 'select', options: [...DRAWER_PLACEMENT] }, // Events bqShow: { action: 'bqOpen' }, bqHide: { action: 'bqClose' }, @@ -21,19 +23,37 @@ const meta: Meta = { }, args: { open: false, + placement: 'left', }, }; export default meta; type Story = StoryObj; -const Template = (args: Args) => html` -
+const Template = (args: Args) => { + const handleOpenDrawer = async () => { + const dialogElem = document.querySelector('bq-drawer'); + await dialogElem.show(); + }; + + return html` + Open Drawer
- Title + +
+ + Title +
Slot @@ -41,26 +61,16 @@ const Template = (args: Args) => html`
Button Button -
-
-
- Title -
- Slot
-
-`; + `; +}; export const Default: Story = { render: Template, args: { - open: true, + open: false, + placement: 'left', }, }; diff --git a/packages/beeq/src/components/drawer/bq-drawer.tsx b/packages/beeq/src/components/drawer/bq-drawer.tsx index c8c1f194e..1f89c7975 100644 --- a/packages/beeq/src/components/drawer/bq-drawer.tsx +++ b/packages/beeq/src/components/drawer/bq-drawer.tsx @@ -1,6 +1,7 @@ import { Component, Element, Event, EventEmitter, h, Host, Method, Prop, State, Watch } from '@stencil/core'; import { enter, leave } from 'el-transition'; +import { TDrawerPlacement } from './bq-drawer.types'; import { hasSlotContent } from '../../shared/utils'; @Component({ @@ -13,8 +14,7 @@ export class BqDrawer { // ==================== private drawerElem: HTMLDivElement; - private footerElem: HTMLDivElement; - private iconElement: HTMLSpanElement; + private footerElem: HTMLElement; // Reference to host HTML element // =================================== @@ -34,6 +34,9 @@ export class BqDrawer { /** If true, the drawer component will be shown */ @Prop({ reflect: true, mutable: true }) open: boolean; + /* Defines the position of the drawer */ + @Prop({ reflect: true, mutable: true }) placement?: TDrawerPlacement = 'left'; + // Prop lifecycle events // ======================= @@ -131,10 +134,6 @@ export class BqDrawer { this.bqAfterClose.emit(); }; - private handleIconSlotChange = () => { - this.hasIcon = hasSlotContent(this.iconElement, 'icon'); - }; - // render() function // Always the last one in the class. // =================================== @@ -145,42 +144,45 @@ export class BqDrawer { class={{ 'is-hidden': !this.open }} aria-hidden={!this.open ? 'true' : 'false'} hidden={!this.open ? 'true' : 'false'} + role="dialog" > -
(this.drawerElem = div)} part="wrapper"> -
- {/* Header */} -
-
(this.iconElement = span)} part="icon"> - + {/* Backdrop */} +
this.hide()}>
+
(this.drawerElem = div)} part="wrapper"> +
+
+
+
-
- +
+ + this.hide()} + > + + +
+
+
+
- {/* CLOSE BUTTON */} - this.hide()} - part="btn-close" - > - - -
- {/* Body */} -
- -
- {this.hasFooter && } - {/* Footer */} -
(this.footerElem = div)} + {this.hasFooter && } + +
+
); diff --git a/packages/beeq/src/components/drawer/bq-drawer.types.ts b/packages/beeq/src/components/drawer/bq-drawer.types.ts new file mode 100644 index 000000000..541d9fc1a --- /dev/null +++ b/packages/beeq/src/components/drawer/bq-drawer.types.ts @@ -0,0 +1,2 @@ +export const DRAWER_PLACEMENT = ['left', 'right'] as const; +export type TDrawerPlacement = (typeof DRAWER_PLACEMENT)[number]; diff --git a/packages/beeq/src/components/drawer/scss/bq-drawer.scss b/packages/beeq/src/components/drawer/scss/bq-drawer.scss index 2ad816cf4..d2460831e 100644 --- a/packages/beeq/src/components/drawer/scss/bq-drawer.scss +++ b/packages/beeq/src/components/drawer/scss/bq-drawer.scss @@ -13,7 +13,24 @@ } .bq-drawer { - @apply relative flex w-auto flex-col gap-[var(--bq-drawer--title-body-gap)] px-[var(--bq-drawer--wrapper-X-padding)] py-[var(--bq-drawer--wrapper-Y-padding)] transition-all; + @apply absolute z-20 flex h-screen w-80 flex-col overflow-auto bg-bg-primary px-[var(--bq-drawer--wrapper-X-padding)] py-[var(--bq-drawer--wrapper-Y-padding)] transition-all; + + &.left { + @apply left-0 top-0; + } + + &.right { + @apply right-0 top-0; + } +} + +/* Styling for the backdrop */ +.bq-drawer-backdrop { + @apply fixed inset-0 z-10 bg-bg-alt opacity-50; +} + +.bq-drawer-backdrop.open { + display: block; } /** @@ -23,6 +40,22 @@ @apply h-fit rounded-s border-0 p-0; } +.bq-drawer__content { + @apply flex flex-1 flex-col gap-[var(--bq-drawer--title-body-gap)]; +} + +.bq-drawer__header { + @apply flex items-center; +} + +.bq-drawer__title { + @apply flex flex-1 items-center justify-between font-bold leading-regular text-text-primary; +} + +.bq-drawer__footer { + @apply flex items-start gap-xs pt-[var(--bq-drawer--footer-top-padding)]; +} + .bq-drawer__body { - @apply h-auto p-[var(--bq-drawer--body-padding)]; + @apply flex-1; } diff --git a/packages/beeq/src/components/drawer/scss/bq-drawer.variables.scss b/packages/beeq/src/components/drawer/scss/bq-drawer.variables.scss index 77c6a1d8f..aeaa75dba 100644 --- a/packages/beeq/src/components/drawer/scss/bq-drawer.variables.scss +++ b/packages/beeq/src/components/drawer/scss/bq-drawer.variables.scss @@ -8,7 +8,8 @@ * @prop ---bq-drawer--body-padding - Drawer default padding for body slot */ --bq-drawer--title-body-gap: theme('spacing.l'); - --bq-drawer--wrapper-X-padding: theme('spacing.m'); - --bq-drawer--wrapper-Y-padding: theme('spacing.l'); + --bq-drawer--wrapper-X-padding: theme('spacing.l'); + --bq-drawer--wrapper-Y-padding: theme('spacing.m'); + --bq-drawer--footer-top-padding: theme('spacing.m'); --bq-drawer--body-padding: theme('spacing.xs'); }