@availity/mui-drawer 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
+
5
+ ## 0.1.0-alpha.0 (2026-02-05)
6
+
7
+
8
+ ### Features
9
+
10
+ * **mui-drawer:** add Drawer component ([e1579ca](https://github.com/Availity/element/commit/e1579caed4975cac296706da14a1b655e6764628))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **mui-drawer:** fix workspace dependencies ([1e8f844](https://github.com/Availity/element/commit/1e8f8448145fc4e3b5971bfa23a0a3deef180922))
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # @availity/mui-drawer
2
+
3
+ > Availity MUI Drawer component to be used with @availity/element design system.
4
+
5
+ [![Version](https://img.shields.io/npm/v/@availity/mui-drawer.svg?style=for-the-badge)](https://www.npmjs.com/package/@availity/mui-drawer)
6
+ [![NPM Downloads](https://img.shields.io/npm/dt/@availity/mui-drawer.svg?style=for-the-badge)](https://www.npmjs.com/package/@availity/mui-drawer)
7
+ [![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)
8
+
9
+ ## Documentation
10
+
11
+ This package extends the MUI Drawer component: [MUI Drawer Docs](https://mui.com/components/drawer/)
12
+
13
+ Live demo and documentation in our [Storybook](https://availity.github.io/element/?path=/docs/components-drawer-introduction--docs)
14
+
15
+ Availity standards for design and usage can be found in the [Availity Design Guide](https://design.availity.com/2e36e50c7)
16
+
17
+ ## Installation
18
+
19
+ ### Import Through @availity/element (Recommended)
20
+
21
+ #### NPM
22
+
23
+ ```bash
24
+ npm install @availity/element
25
+ ```
26
+
27
+ #### Yarn
28
+
29
+ ```bash
30
+ yarn add @availity/element
31
+ ```
32
+
33
+ ### Direct Import
34
+
35
+ #### NPM
36
+
37
+ _This package has a few peer dependencies. Add `@mui/material` & `@emotion/react` to your project if not already installed._
38
+
39
+ ```bash
40
+ npm install @availity/mui-drawer
41
+ ```
42
+
43
+ #### Yarn
44
+
45
+ ```bash
46
+ yarn add @availity/mui-drawer
47
+ ```
48
+
49
+ ### Usage
50
+
51
+ #### Import through @availity/element
52
+
53
+ ```tsx
54
+ import { Drawer } from '@availity/element';
55
+ ```
56
+
57
+ #### Direct import
58
+
59
+ ```tsx
60
+ import { Drawer } from '@availity/mui-drawer';
61
+ ```
@@ -0,0 +1,9 @@
1
+ import { Markdown, Meta } from '@storybook/addon-docs/blocks';
2
+ import ReadMe from './README.md?raw';
3
+ import CHANGELOG from './CHANGELOG.md?raw';
4
+
5
+ <Meta title="Components/Drawer/Introduction" />
6
+
7
+ <Markdown>{ReadMe}</Markdown>
8
+
9
+ <Markdown>{CHANGELOG}</Markdown>
package/jest.config.js ADDED
@@ -0,0 +1,7 @@
1
+ const global = require('../../jest.config.global');
2
+
3
+ module.exports = {
4
+ ...global,
5
+ displayName: 'drawer',
6
+ coverageDirectory: '../../coverage/drawer',
7
+ };
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@availity/mui-drawer",
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "Availity MUI Drawer Component - part of the @availity/element design system",
5
+ "keywords": [
6
+ "react",
7
+ "typescript",
8
+ "availity",
9
+ "mui"
10
+ ],
11
+ "homepage": "https://availity.github.io/element/?path=/docs/components-drawer-introduction--docs",
12
+ "bugs": {
13
+ "url": "https://github.com/Availity/element/issues"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/Availity/element.git",
18
+ "directory": "packages/drawer"
19
+ },
20
+ "license": "MIT",
21
+ "author": "Availity Developers <AVOSS@availity.com>",
22
+ "browser": "./dist/index.js",
23
+ "main": "./dist/index.js",
24
+ "module": "./dist/index.mjs",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ "./package.json": "./package.json",
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.mjs",
31
+ "require": "./dist/index.js"
32
+ }
33
+ },
34
+ "scripts": {
35
+ "build": "tsup src/index.ts --format esm,cjs --dts",
36
+ "dev": "tsup src/index.ts --format esm,cjs --watch --dts",
37
+ "clean": "rm -rf dist",
38
+ "clean:nm": "rm -rf node_modules",
39
+ "publish": "yarn npm publish --tolerate-republish --access public",
40
+ "publish:canary": "yarn npm publish --access public --tag canary"
41
+ },
42
+ "devDependencies": {
43
+ "@availity/mui-checkbox": "workspace:*",
44
+ "@availity/mui-form-utils": "workspace:*",
45
+ "@availity/mui-list": "workspace:*",
46
+ "@mui/material": "^7.3.4",
47
+ "react": "19.2.0",
48
+ "react-dom": "19.2.0",
49
+ "tsup": "^8.4.0",
50
+ "typescript": "^5.4.5"
51
+ },
52
+ "peerDependencies": {
53
+ "@mui/material": "^7.0.0",
54
+ "react": ">=17.0.0"
55
+ },
56
+ "publishConfig": {
57
+ "access": "public"
58
+ },
59
+ "dependencies": {
60
+ "@availity/mui-backdrop": "workspace:*",
61
+ "@availity/mui-button": "workspace:*",
62
+ "@availity/mui-icon": "workspace:*",
63
+ "@availity/mui-layout": "workspace:*",
64
+ "@availity/mui-typography": "workspace:*"
65
+ }
66
+ }
package/project.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "mui-drawer",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "packages/drawer/src",
5
+ "projectType": "library",
6
+ "tags": [],
7
+ "targets": {
8
+ "lint": {
9
+ "executor": "@nx/eslint:lint",
10
+ "options": {
11
+ "eslintConfig": ".eslintrc.json",
12
+ "silent": false,
13
+ "fix": false,
14
+ "cache": true,
15
+ "cacheLocation": "./node_modules/.cache/drawer/.eslintcache",
16
+ "maxWarnings": -1,
17
+ "quiet": false,
18
+ "noEslintrc": false,
19
+ "hasTypeAwareRules": true,
20
+ "cacheStrategy": "metadata"
21
+ }
22
+ },
23
+ "test": {
24
+ "executor": "@nx/jest:jest",
25
+ "outputs": ["{workspaceRoot}/coverage/drawer"],
26
+ "options": {
27
+ "jestConfig": "packages/drawer/jest.config.js"
28
+ }
29
+ },
30
+ "version": {
31
+ "executor": "@jscutlery/semver:version",
32
+ "options": {
33
+ "preset": "conventional",
34
+ "commitMessageFormat": "chore({projectName}): release version ${version} [skip ci]",
35
+ "tagPrefix": "@availity/{projectName}@",
36
+ "trackDeps": true,
37
+ "skipCommitTypes": ["docs"]
38
+ }
39
+ }
40
+ }
41
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './lib/Drawer';
@@ -0,0 +1,133 @@
1
+ import { useState } from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react-vite';
3
+ import { Button, IconButton } from '@availity/mui-button';
4
+ import { Box } from '@availity/mui-layout';
5
+ import { ArrowsRotateIcon, ChartPieIcon, InboxIcon, SendIcon, SettingsIcon } from '@availity/mui-icon';
6
+ import { Checkbox } from '@availity/mui-checkbox';
7
+ import { FormControl, FormControlLabel, FormGroup, FormLabel } from '@availity/mui-form-utils';
8
+ import { List, ListItemButton, ListItemIcon, ListItemText } from '@availity/mui-list';
9
+ import { Drawer, DrawerProps } from './Drawer';
10
+
11
+ const meta: Meta<typeof Drawer> = {
12
+ title: 'Components/Drawer/Drawer',
13
+ component: Drawer,
14
+ tags: ['autodocs'],
15
+ };
16
+
17
+ export default meta;
18
+
19
+ export const _Drawer: StoryObj<typeof Drawer> = {
20
+ render: (args: DrawerProps) => {
21
+ const [open, setOpen] = useState(false);
22
+
23
+ const toggleDrawer = (newOpen: boolean) => () => {
24
+ setOpen(newOpen);
25
+ };
26
+ return (
27
+ <Box height={args.variant === 'persistent' ? '200px' : undefined}>
28
+ <Button onClick={toggleDrawer(!open)}>Toggle Drawer</Button>
29
+ <Drawer {...args} onClose={toggleDrawer(!open)} open={open}></Drawer>
30
+ </Box>
31
+ );
32
+ },
33
+ args: {
34
+ children: `Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur unde suscipit, quam
35
+ beatae rerum inventore consectetur, neque doloribus, cupiditate numquam dignissimos laborum fugiat deleniti? Eum
36
+ quasi quidem quibusdam.`,
37
+ contentPadding: true,
38
+ header: 'Drawer Header',
39
+ actions: (
40
+ <IconButton title="refresh drawer" aria-label="refresh drawer">
41
+ <ArrowsRotateIcon />
42
+ </IconButton>
43
+ ),
44
+ },
45
+ };
46
+
47
+ export const _NavDrawer: StoryObj<typeof Drawer> = {
48
+ render: (args: DrawerProps) => {
49
+ const [open, setOpen] = useState(false);
50
+
51
+ const toggleDrawer = (newOpen: boolean) => () => {
52
+ setOpen(newOpen);
53
+ };
54
+ return (
55
+ <Box height={args.variant === 'persistent' ? '200px' : undefined}>
56
+ <Button onClick={toggleDrawer(!open)}>Toggle Drawer</Button>
57
+ <Drawer {...args} onClose={toggleDrawer(!open)} open={open}></Drawer>
58
+ </Box>
59
+ );
60
+ },
61
+ args: {
62
+ anchor: 'left',
63
+ children: (
64
+ <List disablePadding>
65
+ <ListItemButton divider>
66
+ <ListItemIcon>
67
+ <InboxIcon />
68
+ </ListItemIcon>
69
+ <ListItemText>Inbox</ListItemText>
70
+ </ListItemButton>
71
+ <ListItemButton divider>
72
+ <ListItemIcon>
73
+ <SendIcon />
74
+ </ListItemIcon>
75
+ <ListItemText>Sent</ListItemText>
76
+ </ListItemButton>
77
+ <ListItemButton divider>
78
+ <ListItemIcon>
79
+ <ChartPieIcon />
80
+ </ListItemIcon>
81
+ <ListItemText>Reporting</ListItemText>
82
+ </ListItemButton>
83
+ <ListItemButton divider>
84
+ <ListItemIcon>
85
+ <SettingsIcon />
86
+ </ListItemIcon>
87
+ <ListItemText>Settings</ListItemText>
88
+ </ListItemButton>
89
+ </List>
90
+ ),
91
+ },
92
+ };
93
+
94
+ export const _PersistentDrawer: StoryObj<typeof Drawer> = {
95
+ render: (args: DrawerProps) => {
96
+ const [open, setOpen] = useState(false);
97
+
98
+ const toggleDrawer = (newOpen: boolean) => () => {
99
+ setOpen(newOpen);
100
+ };
101
+ return (
102
+ <Box height={args.variant === 'persistent' ? '200px' : undefined}>
103
+ <Button onClick={toggleDrawer(!open)}>Toggle Drawer</Button>
104
+ <Drawer {...args} onClose={toggleDrawer(!open)} open={open}></Drawer>
105
+ </Box>
106
+ );
107
+ },
108
+ args: {
109
+ children: (
110
+ <FormControl component="fieldset" variant="standard" required>
111
+ <FormLabel component="legend">Group Label</FormLabel>
112
+ <FormGroup>
113
+ <FormControlLabel control={<Checkbox defaultChecked />} label="Label" />
114
+ <FormControlLabel control={<Checkbox />} label="Label 2" />
115
+ <FormControlLabel disabled control={<Checkbox />} label="Label 3" />
116
+ </FormGroup>
117
+ </FormControl>
118
+ ),
119
+ contentPadding: true,
120
+ header: 'Filter',
121
+ variant: 'persistent',
122
+ slotProps: {
123
+ paper: {
124
+ variant: 'outlined',
125
+ },
126
+ },
127
+ actions: (
128
+ <IconButton title="refresh drawer" aria-label="refresh drawer">
129
+ <ArrowsRotateIcon />
130
+ </IconButton>
131
+ ),
132
+ },
133
+ };
@@ -0,0 +1,66 @@
1
+ import { useState } from 'react';
2
+ import { fireEvent, render, waitFor } from '@testing-library/react';
3
+ import { Drawer, DrawerProps } from './Drawer';
4
+
5
+ const TestDrawer = (props: DrawerProps) => {
6
+ const [open, setOpen] = useState(true);
7
+
8
+ return <Drawer {...props} open={open} onClose={() => setOpen(false)} />;
9
+ };
10
+
11
+ describe('Drawer', () => {
12
+ test('should render successfully', () => {
13
+ const { getByText } = render(<TestDrawer>Test</TestDrawer>);
14
+ expect(getByText('Test')).toBeTruthy();
15
+ });
16
+
17
+ test('should close when x is clicked', async () => {
18
+ const { getByText, getByLabelText, queryByText } = render(<TestDrawer header="Test Header">Test</TestDrawer>);
19
+ expect(getByText('Test')).toBeTruthy();
20
+ fireEvent.click(getByLabelText('close drawer'));
21
+ await waitFor(() => expect(queryByText('Test')).toBeFalsy());
22
+ });
23
+
24
+ test('should render header', () => {
25
+ const { getByText } = render(<TestDrawer header="Test Header">Test</TestDrawer>);
26
+ expect(getByText('Test Header')).toBeTruthy();
27
+ });
28
+
29
+ test('should render actions', () => {
30
+ const { getByText } = render(<TestDrawer actions={<button type="button">Test Action</button>}>Test</TestDrawer>);
31
+ expect(getByText('Test Action')).toBeTruthy();
32
+ });
33
+
34
+ test('should apply content padding', () => {
35
+ const { getByText } = render(
36
+ <TestDrawer contentPadding>
37
+ <div>Test</div>
38
+ </TestDrawer>
39
+ );
40
+ expect(getByText('Test').parentElement).toHaveStyle('padding: 0px 24px');
41
+ });
42
+
43
+ test('should conditionally render header and actions', () => {
44
+ const { queryByText, rerender } = render(<TestDrawer>Test</TestDrawer>);
45
+ expect(queryByText('Test Header')).toBeNull();
46
+
47
+ rerender(
48
+ <TestDrawer header="Test Header" actions={<button type="button">Test Action</button>}>
49
+ Test
50
+ </TestDrawer>
51
+ );
52
+ expect(queryByText('Test Header')).toBeTruthy();
53
+ expect(queryByText('Test Action')).toBeTruthy();
54
+ });
55
+
56
+ test('should render with responsive width', () => {
57
+ const { getByRole, rerender } = render(<TestDrawer size="small">Test</TestDrawer>);
58
+ expect(getByRole('dialog')).toHaveStyle('width: 326px');
59
+
60
+ rerender(<TestDrawer size="medium">Test</TestDrawer>);
61
+ expect(getByRole('dialog')).toHaveStyle('width: 400px');
62
+
63
+ rerender(<TestDrawer size="large">Test</TestDrawer>);
64
+ expect(getByRole('dialog')).toHaveStyle('width: 600px');
65
+ });
66
+ });
@@ -0,0 +1,98 @@
1
+ // For bundling purposes, always use the direct import for an mui component, i.e. '@mui/material/xxx'
2
+ import MuiDrawer, { DrawerProps as MuiDrawerProps } from '@mui/material/Drawer';
3
+ import { Backdrop } from '@availity/mui-backdrop';
4
+ import { Box, Grid } from '@availity/mui-layout';
5
+ import { Typography } from '@availity/mui-typography';
6
+ import { IconButton } from '@availity/mui-button';
7
+ import { CloseIcon } from '@availity/mui-icon';
8
+ import { styled } from '@mui/material/styles';
9
+
10
+ export interface DrawerProps extends Omit<MuiDrawerProps, 'slots' | 'elevation'> {
11
+ children?: React.ReactNode;
12
+ slots?: Omit<MuiDrawerProps['slots'], 'backdrop' | 'paper'>;
13
+ actions?: React.ReactNode;
14
+ header?: string;
15
+ size?: 'small' | 'medium' | 'large';
16
+ contentPadding?: boolean;
17
+ }
18
+
19
+ const StyledDrawerHeader = styled(Grid, {
20
+ name: 'MuiDrawer',
21
+ slot: 'AvDrawerHeader',
22
+ })();
23
+
24
+ const StyledDrawerHeaderText = styled(Typography, {
25
+ name: 'MuiDrawer',
26
+ slot: 'AvDrawerHeaderText',
27
+ })();
28
+
29
+ const StyledDrawerContent = styled(Box, {
30
+ name: 'MuiDrawer',
31
+ slot: 'AvDrawerContent',
32
+ })();
33
+
34
+ export const Drawer = ({
35
+ anchor = 'right',
36
+ actions,
37
+ children,
38
+ contentPadding,
39
+ header,
40
+ onClose,
41
+ size = 'medium',
42
+ ...rest
43
+ }: DrawerProps): React.JSX.Element => {
44
+ const drawerHeader = (
45
+ <StyledDrawerHeader container>
46
+ {header && <StyledDrawerHeaderText variant="h5">{header}</StyledDrawerHeaderText>}
47
+ <Grid flexShrink={0} paddingLeft={2} container alignItems="center" justifyContent="flex-end" flexWrap="nowrap">
48
+ {actions && <Grid paddingRight={1}>{actions}</Grid>}
49
+ {onClose && (
50
+ <IconButton
51
+ title="close drawer"
52
+ aria-label="close drawer"
53
+ onClick={() => onClose(!rest.open, 'backdropClick')}
54
+ >
55
+ <CloseIcon />
56
+ </IconButton>
57
+ )}
58
+ </Grid>
59
+ </StyledDrawerHeader>
60
+ );
61
+ const sizes = {
62
+ small: { width: '326px', breakpoint: 350 },
63
+ medium: { width: '400px', breakpoint: 424 },
64
+ large: { width: '600px', breakpoint: 624 },
65
+ };
66
+ const { width, breakpoint } = sizes[size];
67
+
68
+ return (
69
+ <MuiDrawer
70
+ {...rest}
71
+ anchor={anchor}
72
+ onClose={onClose}
73
+ slots={{
74
+ backdrop: Backdrop,
75
+ }}
76
+ slotProps={{
77
+ paper: {
78
+ sx:
79
+ anchor === 'left' || anchor === 'right'
80
+ ? {
81
+ width,
82
+ [`@media (max-width: ${breakpoint}px)`]: {
83
+ width: 'calc(100% - 24px)',
84
+ },
85
+ }
86
+ : undefined,
87
+ },
88
+ transition: {
89
+ easing: { enter: 'cubic-bezier(0.4, 0, 1, 1)', exit: 'cubic-bezier(0.0, 0, 0.2, 1)' },
90
+ timeout: { enter: 225, exit: 195 },
91
+ },
92
+ }}
93
+ >
94
+ {header || actions ? drawerHeader : null}
95
+ <StyledDrawerContent padding={contentPadding ? '0px 24px' : 0}>{children}</StyledDrawerContent>
96
+ </MuiDrawer>
97
+ );
98
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "include": ["."],
4
+ "exclude": ["dist", "build", "node_modules"]
5
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "module": "commonjs",
6
+ "types": ["jest", "node", "@testing-library/jest-dom"],
7
+ "allowJs": true
8
+ },
9
+ "include": ["**/*.test.js", "**/*.test.ts", "**/*.test.tsx", "**/*.d.ts"]
10
+ }