Skip to content

Commit 31338f0

Browse files
authored
Sidebar fixes (#47)
* fix sidebar issues with a simpler, non-modal style also improves some accessibility issues * listen for click instead of mousedown * export constants, add missing event * fix indent * update package version
1 parent faf9454 commit 31338f0

File tree

6 files changed

+190
-125
lines changed

6 files changed

+190
-125
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@openstax/ui-components",
3-
"version": "1.10.1",
3+
"version": "1.10.2",
44
"license": "MIT",
55
"source": "./src/index.ts",
66
"types": "./dist/index.d.ts",
@@ -68,6 +68,7 @@
6868
"@sentry/react": "^7.48.0",
6969
"classnames": "^2.3.1",
7070
"crypto": "npm:crypto-browserify@^3.12.0",
71+
"react-aria": "^3.34.1",
7172
"react-aria-components": "^1.3.1",
7273
"stream": "npm:stream-browserify@^3.0.0"
7374
}

src/components/SidebarNav.spec.tsx

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,19 +90,9 @@ describe("SidebarNav", () => {
9090
});
9191

9292
expect(screen.getByRole("navigation")).not.toHaveClass("collapsed");
93-
94-
act(() => {
95-
fireEvent.click(screen.getByTestId("sidebarnav-toggle"));
96-
});
97-
// Separate act so the classname gets updated
98-
act(() => {
99-
fireEvent.animationEnd(screen.getByTestId("sidebarnav"));
100-
});
101-
102-
expect(screen.getByRole("navigation")).not.toHaveClass("expanding");
10393
});
10494

105-
it("displays modal on mobile", async () => {
95+
it("is dismissable on mobile", async () => {
10696
render(
10797
<SidebarNav isMobile={true}>
10898
{({ setNavIsCollapsed }) => (
@@ -120,14 +110,60 @@ describe("SidebarNav", () => {
120110
fireEvent.click(screen.getByTestId("sidebarnav-toggle"));
121111
});
122112

123-
expect(screen.getByRole("dialog")).toBeInTheDocument();
124-
125113
act(() => {
126114
user.type(document.body, "{Escape}");
127115
});
128116

129117
await waitFor(() => {
130-
expect(screen.queryByTestId("sidebarnav-modal")).not.toBeInTheDocument();
118+
expect(screen.getByRole("navigation")).toHaveClass("collapsed");
119+
});
120+
});
121+
122+
it("collapses on outside click", async () => {
123+
render(
124+
<SidebarNav isMobile={true}>
125+
Content
126+
</SidebarNav>
127+
);
128+
129+
act(() => {
130+
fireEvent.click(screen.getByTestId("sidebarnav-toggle"));
131+
});
132+
133+
fireEvent.mouseDown(screen.getByTestId("sidebarnav"));
134+
135+
await waitFor(() => {
136+
expect(screen.getByTestId("sidebarnav")).not.toHaveClass("collapsed");
137+
});
138+
139+
fireEvent.mouseDown(document);
140+
141+
await waitFor(() => {
142+
expect(screen.getByTestId("sidebarnav")).toHaveClass("collapsed");
143+
});
144+
});
145+
146+
it("doesn't collapse on outside click when mobile is false", async () => {
147+
render(
148+
<SidebarNav isMobile={false}>
149+
Content
150+
</SidebarNav>
151+
);
152+
153+
await waitFor(() => {
154+
expect(screen.getByTestId("sidebarnav")).not.toHaveClass("collapsed");
155+
});
156+
157+
fireEvent.mouseDown(screen.getByTestId("sidebarnav"));
158+
159+
await waitFor(() => {
160+
expect(screen.getByTestId("sidebarnav")).not.toHaveClass("collapsed");
161+
});
162+
163+
fireEvent.mouseDown(document);
164+
165+
await waitFor(() => {
166+
expect(screen.getByTestId("sidebarnav")).not.toHaveClass("collapsed");
131167
});
132168
});
133169
});

src/components/SidebarNav.stories.tsx

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useMatchMediaQuery } from "../../src/hooks";
2-
import styled, { createGlobalStyle } from "styled-components";
2+
import styled, { createGlobalStyle, css } from "styled-components";
33
import { SidebarNav, SidebarNavStyles } from "./SidebarNav";
4+
import React from "react";
45

56
const GlobalStyle = createGlobalStyle`
67
html, body, #ladle-root {
@@ -32,6 +33,7 @@ const Wrapper = styled.div`
3233
`;
3334

3435
const StyledSidebarNav = styled(SidebarNav)`
36+
overflow: auto;
3537
grid-area: nav;
3638
padding: 6rem 2rem;
3739
@@ -47,33 +49,58 @@ const StyledMain = styled.main`
4749
}
4850
`;
4951

52+
const NavItem = styled.li`
53+
a {
54+
text-decoration: none;
55+
color: black;
56+
padding: 0.5rem 1rem;
57+
display: block;
58+
border-radius: 4px;
59+
60+
${(props: { active: boolean }) =>
61+
props.active &&
62+
css`
63+
background-color: #007bff;
64+
color: white;
65+
`}
66+
}
67+
`;
68+
69+
const items = ["Home", "About", "Services", "Contact", ...Array.from({length: 50}, (_, i)=> (i + 1).toString())];
70+
5071
export const Default = () => {
5172
const isMobile = useMatchMediaQuery("(max-width: 620px)");
73+
const [activeItem, setActiveItem] = React.useState<string | null>(null);
5274

5375
return <>
5476
<GlobalStyle />
5577
<Wrapper>
56-
<StyledSidebarNav aria-label="Example Sidebar Nav" isMobile={isMobile}>
57-
{({ navIsCollapsed, setNavIsCollapsed }) => (
58-
<>
78+
<StyledSidebarNav isMobile={isMobile}>
79+
{({ setNavIsCollapsed, navIsCollapsed }) =>
5980
<ul>
60-
<li>
61-
<a href="#" onClick={() => setNavIsCollapsed(!navIsCollapsed)}>
62-
{navIsCollapsed ? "H" : "Home"}
63-
</a>
64-
</li>
65-
<li>
66-
<a href="#" onClick={() => setNavIsCollapsed(!navIsCollapsed)}>
67-
{navIsCollapsed ? "A" : "About"}
68-
</a>
69-
</li>
81+
{items.map((item, index) => (
82+
<NavItem key={index} active={activeItem === item}>
83+
<a href="#" onClick={(e) => {
84+
e.preventDefault();
85+
if (navIsCollapsed) {
86+
setNavIsCollapsed(false);
87+
} else {
88+
setActiveItem(item);
89+
setNavIsCollapsed(isMobile);
90+
}
91+
}}>
92+
{item}
93+
</a>
94+
</NavItem>
95+
))}
7096
</ul>
71-
{!navIsCollapsed ? <p>Some other content</p> : null}
72-
</>
73-
)}
97+
}
7498
</StyledSidebarNav>
75-
<StyledMain style={{ padding: "4rem", marginLeft: (isMobile ? SidebarNavStyles.collapsedWidth : '') }}>
76-
<h1>Main content</h1>
99+
<StyledMain style={{ padding: "4rem", marginLeft: (isMobile ? SidebarNavStyles.collapsedWidth : '') }}>
100+
<h1>
101+
Main content
102+
<p><a href="#">focusable element</a></p>
103+
</h1>
77104
</StyledMain>
78105
</Wrapper>
79106
</>

0 commit comments

Comments
 (0)