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
16 changes: 2 additions & 14 deletions apps/website/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ReactElement, ReactNode, useMemo, useState } from "react";
import type { NextPage } from "next";
import type { AppProps } from "next/app";
import Head from "next/head";
import { DxcApplicationLayout, DxcTextInput, DxcToastsQueue } from "@dxc-technology/halstack-react";
import { DxcApplicationLayout, DxcToastsQueue } from "@dxc-technology/halstack-react";
import MainContent from "@/common/MainContent";
import { useRouter } from "next/router";
import { LinkDetails, LinksSectionDetails, LinksSections } from "@/common/pagesList";
Expand Down Expand Up @@ -108,19 +108,7 @@ export default function App({ Component, pageProps, emotionCache = clientSideEmo
<DxcApplicationLayout.Sidenav
navItems={navItems}
appTitle={isExpanded && <SidenavLogo />}
topContent={
isExpanded && (
<DxcTextInput
placeholder="Search docs"
value={filter}
onChange={({ value }) => {
setFilter(value);
}}
size="fillParent"
clearable
/>
)
}
searchBar={{ placeholder: "Search docs", onChange: (value) => setFilter(value) }}
expanded={isExpanded}
onExpandedChange={() => {
setIsExpanded((currentlyExpanded) => !currentlyExpanded);
Expand Down
22 changes: 22 additions & 0 deletions apps/website/screens/components/sidenav/code/SidenavCodePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ const sectionTypeString = `{
title?: string };
}`;

const searchBarTypeString = `{
autoFocus?: boolean;
disabled?: boolean;
onBlur: (value: string) => void;
onChange: (value: string) => void;
onEnter: (value: string) => void;
placeholder?: string;
}`;

const sections = [
{
title: "Props",
Expand Down Expand Up @@ -147,6 +156,19 @@ const sections = [
<td>Function called when the expansion state of the sidenav changes.</td>
<td>-</td>
</tr>
<tr>
<td>
<DxcFlex direction="column" gap="var(--spacing-gap-xs)" alignItems="baseline">
<StatusBadge status="new" />
searchBar
</DxcFlex>
</td>
<td>
<ExtendedTableCode>{searchBarTypeString}</ExtendedTableCode>
</td>
<td>When provided, a search bar will be rendered at the top of the sidenav.</td>
<td>-</td>
</tr>
<tr>
<td>
<DxcFlex direction="column" gap="var(--spacing-gap-xs)" alignItems="baseline">
Expand Down
4 changes: 3 additions & 1 deletion packages/lib/src/sidenav/Sidenav.accessibility.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ describe("Sidenav component accessibility tests", () => {
],
},
];
const { container } = render(<DxcSidenav navItems={groupItems} appTitle="Application Name" />);
const { container } = render(
<DxcSidenav navItems={groupItems} appTitle="Application Name" searchBar={{ placeholder: "Search..." }} />
);
const results = await axe(container);
expect(results.violations).toHaveLength(0);
});
Expand Down
7 changes: 7 additions & 0 deletions packages/lib/src/sidenav/Sidenav.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ const Sidenav = () => (
<DxcSidenav
navItems={groupItems}
appTitle="Application Name"
searchBar={{ placeholder: "Search..." }}
bottomContent={
<>
<DetailedAvatar />
Expand Down Expand Up @@ -169,6 +170,7 @@ const Sidenav = () => (
<DxcSidenav
navItems={groupItems}
appTitle="Application Name"
searchBar={{ placeholder: "Search..." }}
bottomContent={
<>
<DetailedAvatar />
Expand Down Expand Up @@ -208,6 +210,7 @@ const Collapsed = () => {
<DxcSidenav
navItems={groupItems}
appTitle="App Name"
searchBar={{ placeholder: "Search..." }}
bottomContent={
isExpanded ? (
<>
Expand Down Expand Up @@ -261,6 +264,7 @@ const Collapsed = () => {
<DxcSidenav
navItems={groupItems}
appTitle="App Name"
searchBar={{ placeholder: "Search..." }}
bottomContent={
isExpandedGroupsNoLines ? (
<>
Expand Down Expand Up @@ -314,6 +318,7 @@ const Collapsed = () => {
<DxcSidenav
navItems={groupItems}
appTitle="App Name"
searchBar={{ placeholder: "Search..." }}
bottomContent={
isExpandedGroups ? (
<>
Expand Down Expand Up @@ -373,6 +378,7 @@ const Hovered = () => (
<DxcSidenav
navItems={groupItems}
appTitle="Application Name"
searchBar={{ placeholder: "Search..." }}
bottomContent={
<>
<DetailedAvatar />
Expand Down Expand Up @@ -405,6 +411,7 @@ const SelectedGroup = () => (
<DxcSidenav
navItems={selectedGroupItems}
appTitle="Application name"
searchBar={{ placeholder: "Search..." }}
bottomContent={
<>
<DetailedAvatar />
Expand Down
19 changes: 18 additions & 1 deletion packages/lib/src/sidenav/Sidenav.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "@testing-library/jest-dom";
import { render, fireEvent } from "@testing-library/react";
import { render, fireEvent, waitFor } from "@testing-library/react";
import DxcSidenav from "./Sidenav";
import { ReactNode } from "react";

Expand Down Expand Up @@ -103,4 +103,21 @@ describe("DxcSidenav component", () => {
const collapseButton = getByRole("button", { name: "Collapse" });
expect(collapseButton).toBeTruthy();
});

test("Sidenav renders search bar when searchBar prop is provided", () => {
const { getByPlaceholderText } = render(<DxcSidenav searchBar={{ placeholder: "Search..." }} />);
expect(getByPlaceholderText("Search...")).toBeTruthy();
});

test("Sidenav expands and focuses search input when handleExpandSearch is called", async () => {
const { getByRole, getByPlaceholderText } = render(
<DxcSidenav searchBar={{ placeholder: "Search..." }} defaultExpanded={false} />
);
const expandButton = getByRole("button", { name: "Search" });
fireEvent.click(expandButton);
const searchInput = getByPlaceholderText("Search...") as HTMLInputElement;
await waitFor(() => {
expect(document.activeElement).toBe(searchInput);
});
});
});
22 changes: 20 additions & 2 deletions packages/lib/src/sidenav/Sidenav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import SidenavPropsType from "./types";
import DxcDivider from "../divider/Divider";
import DxcButton from "../button/Button";
import DxcImage from "../image/Image";
import { useContext, useState } from "react";
import { useContext, useRef, useState } from "react";
import DxcNavigationTree from "../navigation-tree/NavigationTree";
import DxcInset from "../inset/Inset";
import ApplicationLayoutContext from "../layout/ApplicationLayoutContext";
import DxcSearchBar from "../search-bar/SearchBar";
import DxcSearchBarTrigger from "../search-bar/SearchBarTrigger";

const SidenavContainer = styled.div<{ expanded: boolean }>`
box-sizing: border-box;
Expand Down Expand Up @@ -67,16 +69,26 @@ const DxcSidenav = ({
expanded,
defaultExpanded = true,
onExpandedChange,
searchBar,
}: SidenavPropsType): JSX.Element => {
const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
const { logo, headerExists } = useContext(ApplicationLayoutContext);
const isControlled = expanded !== undefined;
const isExpanded = isControlled ? !!expanded : internalExpanded;
const shouldFocusSearchBar = useRef(false);

const handleToggle = () => {
const nextState = !isExpanded;
if (!isControlled) setInternalExpanded(nextState);
onExpandedChange?.(nextState);
if (searchBar && nextState === false) {
shouldFocusSearchBar.current = false;
}
};

const handleExpandSearch = () => {
shouldFocusSearchBar.current = true;
handleToggle();
};

return (
Expand Down Expand Up @@ -114,8 +126,14 @@ const DxcSidenav = ({
<SidenavTitle>{appTitle}</SidenavTitle>
</DxcFlex>
</DxcFlex>
{topContent && (
{(topContent || searchBar) && (
<DxcFlex direction="column" gap={"var(--spacing-gap-l)"}>
{searchBar &&
(isExpanded ? (
<DxcSearchBar {...searchBar} autoFocus={shouldFocusSearchBar.current} />
) : (
<DxcSearchBarTrigger onTriggerClick={handleExpandSearch} />
))}
{topContent}
</DxcFlex>
)}
Expand Down
5 changes: 5 additions & 0 deletions packages/lib/src/sidenav/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ReactElement, ReactNode } from "react";
import { SVG } from "../common/utils";
import { SearchBarProps } from "../search-bar/types";

type Section = { items: (Item | GroupItem)[]; title?: string };

Expand Down Expand Up @@ -34,6 +35,10 @@ type Props = {
* Function called when the expansion state of the sidenav changes.
*/
onExpandedChange?: (value: boolean) => void;
/**
* When provided, a search bar will be rendered at the top of the sidenav.
*/
searchBar?: Omit<SearchBarProps, "onCancel">;
/**
* The additional content rendered in the upper part of the sidenav, under the branding.
*/
Expand Down