Skip to content
Open
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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,8 @@
flex-basis: 100%;
}

.headerActions {
display: flex;
align-items: center;

.expand {
display: flex;
align-items: center;
}

.divider {
width: 1px;
height: var(--icon-width-tiny);
background: var(--border-secondary);
margin: var(--2xs) var(--xs);
}
.searchInput {
flex: 1;
}

.tabs {
Expand Down Expand Up @@ -81,6 +68,29 @@
}
}

/* Keeps a section hugging its content instead of growing to fill the body. */
.tabsSection {
flex: 0;
}

/* Spans a section across two rows in the grid body layout. */
.spanTwoRows {
grid-row: span 2;
}

/* Demo-only height utilities to simulate tall, scrollable content. */
.tall {
min-height: 12.5rem;
}

.taller {
min-height: 18.75rem;
}

.tallest {
min-height: 31.25rem;
}

.storyWrapper {
padding: 2rem;
}
Expand All @@ -91,7 +101,3 @@
gap: var(--xs);
margin-top: var(--sm);
}

.contentSection {
padding: 1rem;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { useState } from 'react';
import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
import { fn } from 'storybook/test';
import classNames from 'classnames';
import DsDrawer from './ds-drawer';
import { DsButton } from '../ds-button';
import { DsButtonV3 } from '../ds-button-v3';
import { DsTextInput } from '../ds-text-input';
import { DsIcon } from '../ds-icon';
import { DsDivider } from '../ds-divider';
import { DsStack } from '../ds-stack';
// TODO: Use DsStatusBadge instead.
import { DsSystemStatus } from '../ds-system-status';
import styles from './ds-drawer.stories.module.scss';
Expand Down Expand Up @@ -81,28 +84,27 @@ const DrawerTemplate = (args: DsDrawerProps) => {

export const Default: Story = {
render: DrawerTemplate,
parameters: { docs: { source: { type: 'code' } } },
args: {
children: (
<>
<DsDrawer.Header>
<DsDrawer.Title>
Default Drawer <DsSystemStatus status="healthy" label="Active" />
</DsDrawer.Title>
<div className={styles.headerActions}>
<button className={styles.expand} aria-label="Expand">
<DsIcon icon="open_in_full" size="tiny" />
</button>
<div className={styles.divider} />
<DsStack alignItems="center" gap="var(--xs)">
<DsButtonV3 variant="tertiary" icon="open_in_full" size="tiny" aria-label="Expand" />
<DsDivider orientation="vertical" />
<DsDrawer.CloseTrigger />
</div>
</DsStack>
<DsTypography className={styles.description} variant="body-xs-reg">
This is a description caption under a title.
</DsTypography>
</DsDrawer.Header>
<DsDrawer.Toolbar>
<DsTextInput
placeholder="Search..."
style={{ flex: 1 }}
className={styles.searchInput}
slots={{ startAdornment: <DsIcon icon="search" size="tiny" /> }}
/>
<DsIcon icon="filter_list" size="tiny" />
Expand Down Expand Up @@ -163,6 +165,7 @@ const Tabs = ({ total = 4 }: { total?: number }) => {

export const WithTabs: Story = {
render: DrawerTemplate,
parameters: { docs: { source: { type: 'code' } } },
args: {
columns: 8,
children: (
Expand All @@ -171,19 +174,17 @@ export const WithTabs: Story = {
<DsDrawer.Title>
Drawer with Tabs <DsSystemStatus status="healthy" label="Active" />
</DsDrawer.Title>
<div className={styles.headerActions}>
<button className={styles.expand} aria-label="Expand">
<DsIcon icon="open_in_full" size="tiny" />
</button>
<div className={styles.divider} />
<DsStack alignItems="center" gap="var(--xs)">
<DsButtonV3 variant="tertiary" icon="open_in_full" size="tiny" aria-label="Expand" />
<DsDivider orientation="vertical" />
<DsDrawer.CloseTrigger />
</div>
</DsStack>
<DsTypography className={styles.description} variant="body-xs-reg">
This is a description caption under a title.
</DsTypography>
</DsDrawer.Header>
<DsDrawer.Body className={styles.body}>
<div style={{ flex: 0 }} className={styles.section}>
<div className={classNames(styles.section, styles.tabsSection)}>
<Tabs />
</div>
<div className={styles.section}>
Expand Down Expand Up @@ -212,6 +213,7 @@ export const WithTabs: Story = {

export const WithBackdropAndScroll: Story = {
render: DrawerTemplate,
parameters: { docs: { source: { type: 'code' } } },
args: {
backdrop: true,
children: (
Expand All @@ -225,18 +227,18 @@ export const WithBackdropAndScroll: Story = {
<DsTypography className={styles.sectionHeader} variant="body-md-semi-bold">
Drawer content header
</DsTypography>
<DsTypography style={{ minHeight: '300px' }} variant="heading2" className={styles.sectionContent}>
<DsTypography variant="heading2" className={classNames(styles.sectionContent, styles.taller)}>
Out of scope section
</DsTypography>
</div>
<div className={styles.section}>
<DsTypography className={styles.sectionHeader} variant="body-md-semi-bold">
Drawer content header
</DsTypography>
<DsTypography style={{ minHeight: '200px' }} variant="heading2" className={styles.sectionContent}>
<DsTypography variant="heading2" className={classNames(styles.sectionContent, styles.tall)}>
Out of scope section
</DsTypography>
<DsTypography style={{ minHeight: '500px' }} variant="heading2" className={styles.sectionContent}>
<DsTypography variant="heading2" className={classNames(styles.sectionContent, styles.tallest)}>
Out of scope section
</DsTypography>
</div>
Expand All @@ -248,6 +250,7 @@ export const WithBackdropAndScroll: Story = {

export const DockToStart: Story = {
render: DrawerTemplate,
parameters: { docs: { source: { type: 'code' } } },
args: {
position: 'start',
children: (
Expand Down Expand Up @@ -284,6 +287,7 @@ export const DockToStart: Story = {

export const WithGridContent: Story = {
render: DrawerTemplate,
parameters: { docs: { source: { type: 'code' } } },
args: {
columns: 10,
children: (
Expand All @@ -293,7 +297,7 @@ export const WithGridContent: Story = {
<DsDrawer.CloseTrigger />
</DsDrawer.Header>
<DsDrawer.Body className={styles.bodyGrid}>
<div style={{ gridRow: 'span 2' }} className={styles.section}>
<div className={classNames(styles.section, styles.spanTwoRows)}>
<DsTypography className={styles.sectionHeader} variant="body-md-semi-bold">
Drawer content header
</DsTypography>
Expand Down Expand Up @@ -333,6 +337,7 @@ export const WithGridContent: Story = {
* - 6+ cols → `{ lg: 6, md: 10 }` (up to 10)
*/
export const Responsive: Story = {
parameters: { docs: { source: { type: 'code' } } },
render: function Render() {
const [openDrawer, setOpenDrawer] = useState<string | null>(null);

Expand Down Expand Up @@ -392,6 +397,7 @@ export const ToggleFullSize: Story = {
args: {
columns: 4,
},
parameters: { docs: { source: { type: 'code' } } },
render: function Render(args: DsDrawerProps) {
const [isOpen, setIsOpen] = useState(false);
const [isFullScreen, setIsFullScreen] = useState(false);
Expand All @@ -412,17 +418,17 @@ export const ToggleFullSize: Story = {
>
<DsDrawer.Header>
<DsDrawer.Title>Expandable Drawer</DsDrawer.Title>
<div className={styles.headerActions}>
<button
className={styles.expand}
<DsStack alignItems="center" gap="var(--xs)">
<DsButtonV3
variant="tertiary"
icon={isFullScreen ? 'close_fullscreen' : 'open_in_full'}
size="tiny"
aria-label={isFullScreen ? 'Collapse' : 'Expand'}
onClick={toggleFullScreen}
>
<DsIcon icon={isFullScreen ? 'close_fullscreen' : 'open_in_full'} size="tiny" />
</button>
<div className={styles.divider} />
/>
<DsDivider orientation="vertical" />
<DsDrawer.CloseTrigger />
</div>
</DsStack>
</DsDrawer.Header>
<DsDrawer.Body className={styles.body}>
<div className={styles.section}>
Expand Down Expand Up @@ -450,6 +456,7 @@ export const PreventOpenAutoFocus: Story = {
args: {
onOpenAutoFocus: fn((event: Event) => event.preventDefault()),
},
parameters: { docs: { source: { type: 'code' } } },
render: function Render(args: DsDrawerProps) {
const [query, setQuery] = useState('');

Expand All @@ -476,15 +483,4 @@ export const PreventOpenAutoFocus: Story = {
</div>
);
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);

const input = canvas.getByPlaceholderText(/start typing/i);
await userEvent.type(input, 'hello');

await waitFor(() => expect(canvas.getByRole('dialog')).toBeVisible());

await waitFor(() => expect(input).toHaveFocus());
await expect(args.onOpenAutoFocus).toHaveBeenCalled();
},
};
Loading
Loading