Create crayons mobile drawer components (#14495)

* add MobileDrawer component

* WIP begin navigation component

* rough working version complete

* update story to allow for actual navigation

* add component tests

* add docs

* add HTML variants

* add a max width to the drawer
This commit is contained in:
Suzanne Aitchison 2021-08-16 08:41:26 +01:00 committed by GitHub
parent c16f94f8da
commit a6b4d8e91d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 762 additions and 0 deletions

View file

@ -0,0 +1,26 @@
@import '../config/import';
.drawer-navigation {
&__item {
display: flex;
justify-content: space-between;
a {
color: var(--body-color);
}
a[aria-current='page'] {
color: var(--link-brand-color);
}
.check-icon {
vertical-align: middle;
display: none;
color: var(--link-brand-color);
}
a[aria-current='page'] + .check-icon {
display: block;
}
}
}

View file

@ -0,0 +1,41 @@
@import '../config/import';
.crayons-mobile-drawer {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: var(--z-modal);
&__overlay {
background: var(--base-100);
opacity: 0.5;
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
&__content {
width: 100%;
max-width: 500px;
background: var(--card-bg);
opacity: 1;
position: absolute;
bottom: 0;
left: 50%;
right: 0;
padding: var(--su-4);
border-radius: var(--radius) var(--radius) 0 0;
transform: translateY(100%) translateX(-50%);
animation: slideIn 0.3s ease-in-out forwards;
@keyframes slideIn {
100% {
transform: translateY(0) translateX(-50%);
}
}
}
}

View file

@ -33,5 +33,7 @@
@import 'components/tabs';
@import 'components/tags';
@import 'components/tooltips';
@import 'components/drawers';
@import 'components/drawer-navigation';
@import 'config/generator';

View file

@ -0,0 +1,58 @@
import { h } from 'preact';
import PropTypes from 'prop-types';
import { defaultChildrenPropTypes } from '../../common-prop-types';
import { FocusTrap } from '../../shared/components/focusTrap';
/**
* A component that creates a full-width modal that slides in from the bottom of viewport.
*
*
* @param {object} props
* @param {Array} props.children
* @param {string} props.title The title to be applied to the dialog, surfaced to screen reader users
* @param {Function} props.onClose Action to complete when user opts to close the drawer
*
* @example
* const [isDrawerOpen, setIsDrawerOpen] = useState(false);
* return (
* <div>
* <Button onClick={() => setIsDrawerOpen(true)}>Open drawer</Button>
* {isDrawerOpen && (
* <MobileDrawer
* title="Example MobileDrawer"
* onClose={() => setIsDrawerOpen(false)}
* >
* <h2>Lorem ipsum</h2>
* <Button onClick={() => setIsDrawerOpen(false)}>OK</Button>
* </MobileDrawer>
* )}
* </div>
* );
*/
export const MobileDrawer = ({ children, title, onClose = () => {} }) => {
return (
<div className="crayons-mobile-drawer">
<div className="crayons-mobile-drawer__overlay" />
<FocusTrap
clickOutsideDeactivates
selector=".crayons-mobile-drawer__content"
onDeactivate={onClose}
>
<div
className="crayons-mobile-drawer__content"
role="dialog"
aria-modal="true"
aria-label={title}
>
{children}
</div>
</FocusTrap>
</div>
);
};
MobileDrawer.propTypes = {
children: defaultChildrenPropTypes.isRequired,
title: PropTypes.string.isRequired,
onClose: PropTypes.func,
};

View file

@ -0,0 +1,62 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
// Disabled for the file due to issues disabling for individual JSX lines.
// These are disabled to allow the "click outside to close" functionality
import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
import notes from './drawers.md';
import '../../storybook-utilities/designSystem.scss';
export default {
title: 'Components/MobileDrawer/HTML',
parameters: { notes },
};
export const Default = () => {
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
useEffect(() => {
const keyupListener = (e) => {
if (e.key === 'Escape') {
setIsDrawerOpen(false);
}
};
document.addEventListener('keyup', keyupListener);
return () => document.removeEventListener('keyup', keyupListener);
}, []);
return (
<div>
<button className="crayons-btn" onClick={() => setIsDrawerOpen(true)}>
Open drawer
</button>
{isDrawerOpen && (
<div class="crayons-mobile-drawer">
<div
class="crayons-mobile-drawer__overlay"
onClick={() => setIsDrawerOpen(false)}
/>
<div
aria-label="Example MobileDrawer"
aria-modal="true"
class="crayons-mobile-drawer__content"
role="dialog"
>
<h2 className="mb-4">Lorem ipsum</h2>
<button
className="crayons-btn"
onClick={() => setIsDrawerOpen(false)}
>
OK
</button>
</div>
</div>
)}
</div>
);
};
Default.story = {
name: 'default',
};

View file

@ -0,0 +1,32 @@
import { h } from 'preact';
import { useState } from 'preact/hooks';
import notes from './drawers.md';
import { MobileDrawer, Button } from '@crayons';
export default {
title: 'Components/MobileDrawer',
parameters: { notes },
};
export const Default = () => {
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
return (
<div>
<Button onClick={() => setIsDrawerOpen(true)}>Open drawer</Button>
{isDrawerOpen && (
<MobileDrawer
title="Example MobileDrawer"
onClose={() => setIsDrawerOpen(false)}
>
<h2 className="mb-4">Lorem ipsum</h2>
<Button onClick={() => setIsDrawerOpen(false)}>OK</Button>
</MobileDrawer>
)}
</div>
);
};
Default.story = {
name: 'MobileDrawer',
};

View file

@ -0,0 +1,25 @@
## MobileDrawers
MobileDrawers are intended to be used in small screen sizes only (i.e. for
mobile UI variants), and always appear from the bottom of the viewport. The
button which triggers the MobileDrawer may be located anywhere on the page.
MobileDrawer content should always include at least one interactive item (e.g.
button, link) to make sure focus may be transferred to the new content.
### MobileDrawer accessibility
The MobileDrawer is essentially a
[modal dialog](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/dialog_role).
A `title` should be passed in props to properly label the dialog, and at least
one interactive item should be present in the inner content.
The MobileDrawer component utilises the `focus-trap` library to ensure that:
- When the drawer is opened, focus is transferred to the first interactive item
in that drawer
- When the drawer is closed, focus is transferred back to the button that
activated the drawer
- While the drawer is open, focus is trapped inside so that when a user presses
the Tab key, interactive items behind the drawer are not focused
- When the drawer is open, pressing the Escape key will close it

View file

@ -0,0 +1,82 @@
import { h } from 'preact';
import { axe } from 'jest-axe';
import '@testing-library/jest-dom';
import { render, waitFor } from '@testing-library/preact';
import userEvent from '@testing-library/user-event';
import { MobileDrawer } from '../MobileDrawer';
describe('<MobileDrawer />', () => {
it('should have no a11y violations', async () => {
const { container } = render(
<MobileDrawer title="Example MobileDrawer">
<button>Click me</button>
</MobileDrawer>,
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('should render correctly', () => {
const { container } = render(
<MobileDrawer title="Example MobileDrawer">
<button>Click me</button>
</MobileDrawer>,
);
expect(container.innerHTML).toMatchSnapshot();
});
it('should trap focus inside the drawer by default', async () => {
const { getByRole } = render(
<div>
<button>Outside drawer button</button>
<MobileDrawer title="Example MobileDrawer">
<button>Inside drawer button</button>
<button>Inside drawer button 2</button>
</MobileDrawer>
</div>,
);
const innerDrawerButton = getByRole('button', {
name: 'Inside drawer button',
});
await waitFor(() => expect(innerDrawerButton).toHaveFocus());
userEvent.tab();
expect(
getByRole('button', { name: 'Inside drawer button 2' }),
).toHaveFocus();
userEvent.tab();
expect(innerDrawerButton).toHaveFocus();
});
it('should close when Escape is pressed', () => {
const onClose = jest.fn();
const { container } = render(
<MobileDrawer title="Example MobileDrawer" onClose={onClose}>
<button>Inner button</button>
</MobileDrawer>,
);
userEvent.type(container, '{esc}');
expect(onClose).toHaveBeenCalled();
});
it('should close on click outside', () => {
const onClose = jest.fn();
const { getByText } = render(
<div>
<p>Outside content</p>
<MobileDrawer title="Example MobileDrawer" onClose={onClose}>
<button>Inner button</button>
</MobileDrawer>
,
</div>,
);
userEvent.click(getByText('Outside content'));
expect(onClose).toHaveBeenCalled();
});
});

View file

@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<MobileDrawer /> should render correctly 1`] = `"<div class=\\"crayons-mobile-drawer\\"><div class=\\"crayons-mobile-drawer__overlay\\"></div><div class=\\"crayons-mobile-drawer__content\\" role=\\"dialog\\" aria-modal=\\"true\\" aria-label=\\"Example MobileDrawer\\"><button>Click me</button></div></div>"`;

View file

@ -0,0 +1 @@
export * from './MobileDrawer';

View file

@ -4,3 +4,5 @@ export * from '@crayons/Dropdown';
export * from '@crayons/formElements';
export * from '@crayons/Modal';
export * from '@crayons/Spinner';
export * from '@crayons/MobileDrawer';
export * from '@crayons/navigation';

View file

@ -0,0 +1,115 @@
import { h, Fragment } from 'preact';
import { useState } from 'preact/hooks';
import PropTypes from 'prop-types';
import { MobileDrawer } from '@crayons/MobileDrawer';
import { Button } from '@crayons/Button';
const OverflowIcon = () => (
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M7 12a2 2 0 11-4 0 2 2 0 014 0zm7 0a2 2 0 11-4 0 2 2 0 014 0zm5 2a2 2 0 100-4 2 2 0 000 4z"
/>
</svg>
);
const CheckIcon = () => (
<svg
aria-hidden="true"
className="check-icon"
fill="currentColor"
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414 4.95 4.95z" />
</svg>
);
/**
* Renders a page heading with a button which activates a <MobileDrawer /> with a list of the given navigation links.
*
* @param {object} props
* @param {number} headingLevel The level of heading to render as the page title (e.g. 1-6)
* @param {string} navigationTitle The title to be used for the navigation element (e.g. 'Feed timeframes')
* @param {Array} navigationLinks An array of navigationLink objects to display
*
* @example
* <MobileDrawerNavigation
* headingLevel={2}
* navigationTitle="Feed options"
* navigationLinks={links} />
*/
export const MobileDrawerNavigation = ({
headingLevel,
navigationTitle,
navigationLinks,
}) => {
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
const currentPage = navigationLinks.find((item) => item.isCurrentPage);
const Heading = `h${headingLevel}`;
return (
<Fragment>
<div className="flex justify-between">
<Heading>{currentPage.displayName}</Heading>
<Button
aria-label={navigationTitle}
icon={OverflowIcon}
size="s"
contentType="icon"
variant="ghost"
onClick={() => setIsDrawerOpen(true)}
/>
</div>
{isDrawerOpen && (
<MobileDrawer
title={navigationTitle}
onClose={() => setIsDrawerOpen(false)}
>
<nav aria-label={navigationTitle} className="drawer-navigation">
<ul className="list-none">
{navigationLinks.map((linkDetails) => {
const { url, isCurrentPage, displayName } = linkDetails;
return (
<li
key={`link-${url}`}
className="drawer-navigation__item py-2"
>
<a href={url} aria-current={isCurrentPage ? 'page' : null}>
{displayName}
</a>
<CheckIcon />
</li>
);
})}
</ul>
</nav>
<Button
variant="secondary"
className="w-100 mt-4"
onClick={() => setIsDrawerOpen(false)}
>
Cancel
</Button>
</MobileDrawer>
)}
</Fragment>
);
};
MobileDrawerNavigation.propTypes = {
headingLevel: PropTypes.oneOf([1, 2, 3, 4, 5, 6]).isRequired,
navigationTitle: PropTypes.string.isRequired,
navigationLinks: PropTypes.arrayOf(
PropTypes.shape({
url: PropTypes.string,
isCurrentPage: PropTypes.bool,
displayName: PropTypes.string,
}),
).isRequired,
};

View file

@ -0,0 +1,54 @@
import { h, Fragment } from 'preact';
import notes from './mobileDrawerNavigation.md';
import { MobileDrawerNavigation } from '@crayons';
export default {
title: 'App Components/MobileDrawerNavigation',
parameters: { notes },
};
export const Default = () => {
const { href, hash } = window.location;
const indexOfHash = href.indexOf(hash) || href.length;
const baseStoryUrl = href.substr(0, indexOfHash);
const links = [
{
url: baseStoryUrl,
displayName: 'Drawer Navigation',
isCurrentPage: href === baseStoryUrl,
},
{
url: `${baseStoryUrl}/#2`,
displayName: 'Example link 2',
isCurrentPage: `#2` === hash,
},
{
url: `${baseStoryUrl}/#3`,
displayName: 'Example link 3',
isCurrentPage: `#3` === hash,
},
{
url: `${baseStoryUrl}/#4`,
displayName: 'Example link 4',
isCurrentPage: `#4` === hash,
},
];
return (
<Fragment>
<MobileDrawerNavigation
headingLevel={2}
navigationTitle="Example MobileDrawerNavigation"
navigationLinks={links}
/>
<p className="my-4">
Click on the button to view and select navigation links.
</p>
</Fragment>
);
};
Default.story = {
name: 'MobileDrawerNavigation',
};

View file

@ -0,0 +1,139 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
// Disabled for the file due to issues disabling for individual JSX lines.
// These are disabled to allow the "click outside to close" functionality
import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
import notes from './mobileDrawerNavigation.md';
export default {
title: 'App Components/MobileDrawerNavigation/HTML',
parameters: { notes },
};
export const Default = () => {
const [isNavOpen, setIsNavOpen] = useState(false);
const { href, hash } = window.location;
const indexOfHash = href.indexOf(hash) || href.length;
const baseStoryUrl = href.substr(0, indexOfHash);
useEffect(() => {
const keyupListener = (e) => {
if (e.key === 'Escape') {
setIsNavOpen(false);
}
};
document.addEventListener('keyup', keyupListener);
return () => document.removeEventListener('keyup', keyupListener);
}, []);
return (
<div>
<div class="flex justify-between">
<h1>Link 1</h1>
<button
onClick={() => setIsNavOpen(true)}
aria-label="Test navigation"
class="crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon"
type="button"
>
<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg">
<path
clip-rule="evenodd"
d="M7 12a2 2 0 11-4 0 2 2 0 014 0zm7 0a2 2 0 11-4 0 2 2 0 014 0zm5 2a2 2 0 100-4 2 2 0 000 4z"
fill-rule="evenodd"
/>
</svg>
</button>
</div>
{isNavOpen && (
<div class="crayons-mobile-drawer">
<div
class="crayons-mobile-drawer__overlay"
onClick={() => setIsNavOpen(false)}
/>
<div
aria-label="Test navigation"
aria-modal="true"
class="crayons-mobile-drawer__content"
role="dialog"
>
<nav aria-label="Test navigation" class="drawer-navigation">
<ul class="list-none">
<li class="drawer-navigation__item py-2">
<a
aria-current={href === baseStoryUrl ? 'page' : null}
href={baseStoryUrl}
>
Link 1
</a>
<svg
aria-hidden="true"
class="check-icon"
fill="currentColor"
height="24"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414 4.95 4.95z" />
</svg>
</li>
<li class="drawer-navigation__item py-2">
<a
href={`${baseStoryUrl}/#2`}
aria-current={`#2` === hash ? 'page' : null}
>
Link 2
</a>
<svg
aria-hidden="true"
class="check-icon"
fill="currentColor"
height="24"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414 4.95 4.95z" />
</svg>
</li>
<li class="drawer-navigation__item py-2">
<a
href={`${baseStoryUrl}/#3`}
aria-current={`#3` === hash ? 'page' : null}
>
Link 3
</a>
<svg
aria-hidden="true"
class="check-icon"
fill="currentColor"
height="24"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414 4.95 4.95z" />
</svg>
</li>
</ul>
</nav>
<button
class="crayons-btn crayons-btn--secondary w-100 mt-4"
type="button"
onClick={() => setIsNavOpen(false)}
>
Cancel
</button>
</div>
</div>
)}
</div>
);
};
Default.story = {
name: 'MobileDrawerNavigation',
};

View file

@ -0,0 +1,29 @@
## MobileDrawerNavigation
The MobileDrawerNavigation component is intended to be used on small
(mobile-sized) screens only. It can be used as an alternative to the larger
navigation tab component.
The component is responsible for showing:
- The heading of the currently selected page
- A navigation dialog with the given links
This component is best placed at the top of a page. The dialog utilizes
`<MobileDrawer />`, and will appear from the bottom of the screen.
### MobileDrawerNavigation Accessibility
The MobileDrawerNavigation component requires a `navigationTitle` prop which
will be used for:
- The activating button for the navigation dialog
- The label of the navigation dialog
- The label of the navigation element containing the links
This helps ensure accessible element names are surfaced to all users.
The component also requires a `headingLevel` prop which is used to determine the
HTML element used for the displayed current page title (e.g. `1` will render an
`h1`). Appropriate consideration should be given to which heading level is
semantically correct for the location the component is rendered.

View file

@ -0,0 +1,85 @@
import { h } from 'preact';
import { axe } from 'jest-axe';
import '@testing-library/jest-dom';
import { render, waitFor } from '@testing-library/preact';
import { MobileDrawerNavigation } from '../MobileDrawerNavigation';
describe('<MobileDrawerNavigation />', () => {
const testLinks = [
{ url: '/#1', displayName: 'Link 1', isCurrentPage: true },
{ url: '/#2', displayName: 'Link 2', isCurrentPage: false },
{ url: '/#3', displayName: 'Link 3', isCurrentPage: false },
];
it('should have no a11y violations when closed', async () => {
const { container } = render(
<MobileDrawerNavigation
navigationTitle="Test navigation"
headingLevel={1}
navigationLinks={testLinks}
/>,
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('should have no a11y violations when open', async () => {
const { container, getByRole } = render(
<MobileDrawerNavigation
navigationTitle="Test navigation"
headingLevel={1}
navigationLinks={testLinks}
/>,
);
getByRole('button', { name: 'Test navigation' }).click();
await waitFor(() => getByRole('navigation', { name: 'Test navigation' }));
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('should render a heading with a button when closed', () => {
const { container } = render(
<MobileDrawerNavigation
navigationTitle="Test navigation"
headingLevel={1}
navigationLinks={testLinks}
/>,
);
expect(container.innerHTML).toMatchSnapshot();
});
it('should render a navigation with a checkmark for current page when open', async () => {
const { container, getByRole } = render(
<MobileDrawerNavigation
navigationTitle="Test navigation"
headingLevel={1}
navigationLinks={testLinks}
/>,
);
getByRole('button', { name: 'Test navigation' }).click();
await waitFor(() => getByRole('navigation', { name: 'Test navigation' }));
expect(container.innerHTML).toMatchSnapshot();
});
it('should render all links', async () => {
const { getByRole } = render(
<MobileDrawerNavigation
navigationTitle="Test navigation"
headingLevel={1}
navigationLinks={testLinks}
/>,
);
getByRole('button', { name: 'Test navigation' }).click();
await waitFor(() => getByRole('navigation', { name: 'Test navigation' }));
expect(getByRole('link', { name: 'Link 1' })).toBeInTheDocument();
expect(getByRole('link', { name: 'Link 2' })).toBeInTheDocument();
expect(getByRole('link', { name: 'Link 3' })).toBeInTheDocument();
});
});

View file

@ -0,0 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<MobileDrawerNavigation /> should render a heading with a button when closed 1`] = `"<div class=\\"flex justify-between\\"><h1>Link 1</h1><button class=\\"crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon\\" type=\\"button\\" aria-label=\\"Test navigation\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\"><path fill-rule=\\"evenodd\\" clip-rule=\\"evenodd\\" d=\\"M7 12a2 2 0 11-4 0 2 2 0 014 0zm7 0a2 2 0 11-4 0 2 2 0 014 0zm5 2a2 2 0 100-4 2 2 0 000 4z\\"></path></svg></button></div>"`;
exports[`<MobileDrawerNavigation /> should render a navigation with a checkmark for current page when open 1`] = `"<div class=\\"flex justify-between\\"><h1>Link 1</h1><button class=\\"crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon\\" type=\\"button\\" aria-label=\\"Test navigation\\"><svg width=\\"24\\" height=\\"24\\" xmlns=\\"http://www.w3.org/2000/svg\\"><path fill-rule=\\"evenodd\\" clip-rule=\\"evenodd\\" d=\\"M7 12a2 2 0 11-4 0 2 2 0 014 0zm7 0a2 2 0 11-4 0 2 2 0 014 0zm5 2a2 2 0 100-4 2 2 0 000 4z\\"></path></svg></button></div><div class=\\"crayons-mobile-drawer\\"><div class=\\"crayons-mobile-drawer__overlay\\"></div><div class=\\"crayons-mobile-drawer__content\\" role=\\"dialog\\" aria-modal=\\"true\\" aria-label=\\"Test navigation\\"><nav aria-label=\\"Test navigation\\" class=\\"drawer-navigation\\"><ul class=\\"list-none\\"><li class=\\"drawer-navigation__item py-2\\"><a href=\\"/#1\\" aria-current=\\"page\\">Link 1</a><svg aria-hidden=\\"true\\" class=\\"check-icon\\" fill=\\"currentColor\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" xmlns=\\"http://www.w3.org/2000/svg\\"><path d=\\"M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414 4.95 4.95z\\"></path></svg></li><li class=\\"drawer-navigation__item py-2\\"><a href=\\"/#2\\">Link 2</a><svg aria-hidden=\\"true\\" class=\\"check-icon\\" fill=\\"currentColor\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" xmlns=\\"http://www.w3.org/2000/svg\\"><path d=\\"M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414 4.95 4.95z\\"></path></svg></li><li class=\\"drawer-navigation__item py-2\\"><a href=\\"/#3\\">Link 3</a><svg aria-hidden=\\"true\\" class=\\"check-icon\\" fill=\\"currentColor\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" xmlns=\\"http://www.w3.org/2000/svg\\"><path d=\\"M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414 4.95 4.95z\\"></path></svg></li></ul></nav><button class=\\"crayons-btn crayons-btn--secondary w-100 mt-4\\" type=\\"button\\">Cancel</button></div></div>"`;

View file

@ -0,0 +1 @@
export * from './MobileDrawerNavigation/MobileDrawerNavigation';