Skip to content
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
Empty file added packages/drawer/CHANGELOG.md
Empty file.
61 changes: 61 additions & 0 deletions packages/drawer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# @availity/mui-drawer

> Availity MUI Drawer component to be used with @availity/element design system.

[![Version](https://img.shields.io/npm/v/@availity/mui-drawer.svg?style=for-the-badge)](https://www.npmjs.com/package/@availity/mui-drawer)
[![NPM Downloads](https://img.shields.io/npm/dt/@availity/mui-drawer.svg?style=for-the-badge)](https://www.npmjs.com/package/@availity/mui-drawer)
[![Dependency Status](https://img.shields.io/librariesio/release/npm/@availity/mui-drawer?style=for-the-badge)](https://github.com/Availity/element/blob/main/packages/mui-drawer/package.json)

## Documentation

This package extends the MUI Drawer component: [MUI Drawer Docs](https://mui.com/components/drawer/)

Live demo and documentation in our [Storybook](https://availity.github.io/element/?path=/docs/components-drawer-introduction--docs)

Availity standards for design and usage can be found in the [Availity Design Guide](https://design.availity.com/2e36e50c7)

## Installation

### Import Through @availity/element (Recommended)

#### NPM

```bash
npm install @availity/element
```

#### Yarn

```bash
yarn add @availity/element
```

### Direct Import

#### NPM

_This package has a few peer dependencies. Add `@mui/material` & `@emotion/react` to your project if not already installed._

```bash
npm install @availity/mui-drawer
```

#### Yarn

```bash
yarn add @availity/mui-drawer
```

### Usage

#### Import through @availity/element

```tsx
import { Drawer } from '@availity/element';
```

#### Direct import

```tsx
import { Drawer } from '@availity/mui-drawer';
```
9 changes: 9 additions & 0 deletions packages/drawer/introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Markdown, Meta } from '@storybook/addon-docs/blocks';
import ReadMe from './README.md?raw';
import CHANGELOG from './CHANGELOG.md?raw';

<Meta title="Components/Drawer/Introduction" />

<Markdown>{ReadMe}</Markdown>

<Markdown>{CHANGELOG}</Markdown>
7 changes: 7 additions & 0 deletions packages/drawer/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const global = require('../../jest.config.global');

module.exports = {
...global,
displayName: 'drawer',
coverageDirectory: '../../coverage/drawer',
};
66 changes: 66 additions & 0 deletions packages/drawer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "@availity/mui-drawer",
"version": "0.0.0",
"description": "Availity MUI Drawer Component - part of the @availity/element design system",
"keywords": [
"react",
"typescript",
"availity",
"mui"
],
"homepage": "https://availity.github.io/element/?path=/docs/components-drawer-introduction--docs",
"bugs": {
"url": "https://github.com/Availity/element/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/Availity/element.git",
"directory": "packages/drawer"
},
"license": "MIT",
"author": "Availity Developers <AVOSS@availity.com>",
"browser": "./dist/index.js",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
"./package.json": "./package.json",
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
},
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts",
"dev": "tsup src/index.ts --format esm,cjs --watch --dts",
"clean": "rm -rf dist",
"clean:nm": "rm -rf node_modules",
"publish": "yarn npm publish --tolerate-republish --access public",
"publish:canary": "yarn npm publish --access public --tag canary"
},
"devDependencies": {
"@availity/mui-checkbox": "workspace:^",
"@availity/mui-form-utils": "workspace:^",
"@availity/mui-list": "workspace:^",
"@mui/material": "^7.3.4",
"react": "19.2.0",
"react-dom": "19.2.0",
"tsup": "^8.4.0",
"typescript": "^5.4.5"
},
"peerDependencies": {
"@mui/material": "^7.0.0",
"react": ">=17.0.0"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"@availity/mui-backdrop": "workspace:^",
"@availity/mui-button": "workspace:^",
"@availity/mui-icon": "workspace:^",
"@availity/mui-layout": "workspace:^",
"@availity/mui-typography": "workspace:^"
}
}
41 changes: 41 additions & 0 deletions packages/drawer/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "mui-drawer",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/drawer/src",
"projectType": "library",
"tags": [],
"targets": {
"lint": {
"executor": "@nx/eslint:lint",
"options": {
"eslintConfig": ".eslintrc.json",
"silent": false,
"fix": false,
"cache": true,
"cacheLocation": "./node_modules/.cache/drawer/.eslintcache",
"maxWarnings": -1,
"quiet": false,
"noEslintrc": false,
"hasTypeAwareRules": true,
"cacheStrategy": "metadata"
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/drawer"],
"options": {
"jestConfig": "packages/drawer/jest.config.js"
}
},
"version": {
"executor": "@jscutlery/semver:version",
"options": {
"preset": "conventional",
"commitMessageFormat": "chore({projectName}): release version ${version} [skip ci]",
"tagPrefix": "@availity/{projectName}@",
"trackDeps": true,
"skipCommitTypes": ["docs"]
}
}
}
}
1 change: 1 addition & 0 deletions packages/drawer/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './lib/Drawer';
133 changes: 133 additions & 0 deletions packages/drawer/src/lib/Drawer.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { useState } from 'react';
import type { Meta, StoryObj } from '@storybook/react-vite';
import { Button, IconButton } from '@availity/mui-button';
import { Box } from '@availity/mui-layout';
import { ArrowsRotateIcon, ChartPieIcon, InboxIcon, SendIcon, SettingsIcon } from '@availity/mui-icon';
import { Checkbox } from '@availity/mui-checkbox';
import { FormControl, FormControlLabel, FormGroup, FormLabel } from '@availity/mui-form-utils';
import { List, ListItemButton, ListItemIcon, ListItemText } from '@availity/mui-list';
import { Drawer, DrawerProps } from './Drawer';

const meta: Meta<typeof Drawer> = {
title: 'Components/Drawer/Drawer',
component: Drawer,
tags: ['autodocs'],
};

export default meta;

export const _Drawer: StoryObj<typeof Drawer> = {
render: (args: DrawerProps) => {
const [open, setOpen] = useState(false);

const toggleDrawer = (newOpen: boolean) => () => {
setOpen(newOpen);
};
return (
<Box height={args.variant === 'persistent' ? '200px' : undefined}>
<Button onClick={toggleDrawer(!open)}>Toggle Drawer</Button>
<Drawer {...args} onClose={toggleDrawer(!open)} open={open}></Drawer>
</Box>
);
},
args: {
children: `Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur unde suscipit, quam
beatae rerum inventore consectetur, neque doloribus, cupiditate numquam dignissimos laborum fugiat deleniti? Eum
quasi quidem quibusdam.`,
contentPadding: true,
header: 'Drawer Header',
actions: (
<IconButton title="refresh drawer" aria-label="refresh drawer">
<ArrowsRotateIcon />
</IconButton>
),
},
};

export const _NavDrawer: StoryObj<typeof Drawer> = {
render: (args: DrawerProps) => {
const [open, setOpen] = useState(false);

const toggleDrawer = (newOpen: boolean) => () => {
setOpen(newOpen);
};
return (
<Box height={args.variant === 'persistent' ? '200px' : undefined}>
<Button onClick={toggleDrawer(!open)}>Toggle Drawer</Button>
<Drawer {...args} onClose={toggleDrawer(!open)} open={open}></Drawer>
</Box>
);
},
args: {
anchor: 'left',
children: (
<List disablePadding>
<ListItemButton divider>
<ListItemIcon>
<InboxIcon />
</ListItemIcon>
<ListItemText>Inbox</ListItemText>
</ListItemButton>
<ListItemButton divider>
<ListItemIcon>
<SendIcon />
</ListItemIcon>
<ListItemText>Sent</ListItemText>
</ListItemButton>
<ListItemButton divider>
<ListItemIcon>
<ChartPieIcon />
</ListItemIcon>
<ListItemText>Reporting</ListItemText>
</ListItemButton>
<ListItemButton divider>
<ListItemIcon>
<SettingsIcon />
</ListItemIcon>
<ListItemText>Settings</ListItemText>
</ListItemButton>
</List>
),
},
};

export const _PersistentDrawer: StoryObj<typeof Drawer> = {
render: (args: DrawerProps) => {
const [open, setOpen] = useState(false);

const toggleDrawer = (newOpen: boolean) => () => {
setOpen(newOpen);
};
return (
<Box height={args.variant === 'persistent' ? '200px' : undefined}>
<Button onClick={toggleDrawer(!open)}>Toggle Drawer</Button>
<Drawer {...args} onClose={toggleDrawer(!open)} open={open}></Drawer>
</Box>
);
},
args: {
children: (
<FormControl component="fieldset" variant="standard" required>
<FormLabel component="legend">Group Label</FormLabel>
<FormGroup>
<FormControlLabel control={<Checkbox defaultChecked />} label="Label" />
<FormControlLabel control={<Checkbox />} label="Label 2" />
<FormControlLabel disabled control={<Checkbox />} label="Label 3" />
</FormGroup>
</FormControl>
),
contentPadding: true,
header: 'Filter',
variant: 'persistent',
slotProps: {
paper: {
variant: 'outlined',
},
},
actions: (
<IconButton title="refresh drawer" aria-label="refresh drawer">
<ArrowsRotateIcon />
</IconButton>
),
},
};
66 changes: 66 additions & 0 deletions packages/drawer/src/lib/Drawer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useState } from 'react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { Drawer, DrawerProps } from './Drawer';

const TestDrawer = (props: DrawerProps) => {
const [open, setOpen] = useState(true);

return <Drawer {...props} open={open} onClose={() => setOpen(false)} />;
};

describe('Drawer', () => {
test('should render successfully', () => {
const { getByText } = render(<TestDrawer>Test</TestDrawer>);
expect(getByText('Test')).toBeTruthy();
});

test('should close when x is clicked', async () => {
const { getByText, getByLabelText, queryByText } = render(<TestDrawer header="Test Header">Test</TestDrawer>);
expect(getByText('Test')).toBeTruthy();
fireEvent.click(getByLabelText('close drawer'));
await waitFor(() => expect(queryByText('Test')).toBeFalsy());
});

test('should render header', () => {
const { getByText } = render(<TestDrawer header="Test Header">Test</TestDrawer>);
expect(getByText('Test Header')).toBeTruthy();
});

test('should render actions', () => {
const { getByText } = render(<TestDrawer actions={<button type="button">Test Action</button>}>Test</TestDrawer>);
expect(getByText('Test Action')).toBeTruthy();
});

test('should apply content padding', () => {
const { getByText } = render(
<TestDrawer contentPadding>
<div>Test</div>
</TestDrawer>
);
expect(getByText('Test').parentElement).toHaveStyle('padding: 0px 24px');
});

test('should conditionally render header and actions', () => {
const { queryByText, rerender } = render(<TestDrawer>Test</TestDrawer>);
expect(queryByText('Test Header')).toBeNull();

rerender(
<TestDrawer header="Test Header" actions={<button type="button">Test Action</button>}>
Test
</TestDrawer>
);
expect(queryByText('Test Header')).toBeTruthy();
expect(queryByText('Test Action')).toBeTruthy();
});

test('should render with responsive width', () => {
const { getByRole, rerender } = render(<TestDrawer size="small">Test</TestDrawer>);
expect(getByRole('dialog')).toHaveStyle('width: 326px');

rerender(<TestDrawer size="medium">Test</TestDrawer>);
expect(getByRole('dialog')).toHaveStyle('width: 400px');

rerender(<TestDrawer size="large">Test</TestDrawer>);
expect(getByRole('dialog')).toHaveStyle('width: 600px');
});
});
Loading