Skip to content

Commit 9713d2c

Browse files
committed
Made changes in sidenav API to fit our documentation website
1 parent d90b881 commit 9713d2c

File tree

18 files changed

+208
-324
lines changed

18 files changed

+208
-324
lines changed

apps/website/pages/_app.tsx

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
import { ReactElement, ReactNode, useMemo, useState } from "react";
1+
import { ReactElement, ReactNode, useEffect } from "react";
22
import type { NextPage } from "next";
33
import type { AppProps } from "next/app";
44
import Head from "next/head";
5-
import { DxcApplicationLayout, DxcTextInput, DxcToastsQueue } from "@dxc-technology/halstack-react";
6-
import SidenavLogo from "@/common/sidenav/SidenavLogo";
5+
import { DxcApplicationLayout, DxcToastsQueue } from "@dxc-technology/halstack-react";
76
import MainContent from "@/common/MainContent";
87
import { useRouter } from "next/router";
98
import { LinksSectionDetails, LinksSections } from "@/common/pagesList";
10-
import Link from "next/link";
119
import StatusBadge from "@/common/StatusBadge";
1210
import "../global-styles.css";
1311
import createCache, { EmotionCache } from "@emotion/cache";
1412
import { CacheProvider } from "@emotion/react";
13+
import { usePathname } from "next/navigation";
1514

1615
type NextPageWithLayout = NextPage & {
1716
getLayout?: (_page: ReactElement) => ReactNode;
@@ -26,54 +25,69 @@ const clientSideEmotionCache = createCache({ key: "css", prepend: true });
2625
export default function App({ Component, pageProps, emotionCache = clientSideEmotionCache }: AppPropsWithLayout) {
2726
const getLayout = Component.getLayout || ((page) => page);
2827
const componentWithLayout = getLayout(<Component {...pageProps} />);
29-
const [filter, setFilter] = useState("");
30-
const { asPath: currentPath } = useRouter();
31-
const filteredLinks = useMemo(() => {
32-
const filtered: LinksSectionDetails[] = [];
33-
LinksSections.map((section) => {
34-
const sectionFilteredLinks = section?.links.filter((link) =>
35-
link.label.toLowerCase().includes(filter.toLowerCase())
36-
);
37-
if (sectionFilteredLinks.length) {
38-
filtered.push({ label: section.label, links: sectionFilteredLinks });
39-
}
40-
});
41-
return filtered;
42-
}, [filter]);
28+
const router = useRouter();
29+
const pathname = usePathname();
30+
// const [filter, setFilter] = useState("");
31+
// const filteredLinks = useMemo(() => {
32+
// const filtered: LinksSectionDetails[] = [];
33+
// LinksSections.map((section) => {
34+
// const sectionFilteredLinks = section?.links.filter((link) =>
35+
// link.label.toLowerCase().includes(filter.toLowerCase())
36+
// );
37+
// if (sectionFilteredLinks.length) {
38+
// filtered.push({ label: section.label, links: sectionFilteredLinks });
39+
// }
40+
// });
41+
// return filtered;
42+
// }, [filter]);
43+
44+
const mapLinksToGroupItems = (sections: LinksSectionDetails[]) => {
45+
const matchPaths = (linkPath: string) => {
46+
const desiredPaths = [linkPath, `${linkPath}/code`];
47+
const pathToBeMatched = pathname?.split("#")[0]?.slice(0, -1);
48+
return pathToBeMatched ? desiredPaths.includes(pathToBeMatched) : false;
49+
};
4350

44-
const matchPaths = (linkPath: string) => {
45-
const desiredPaths = [linkPath, `${linkPath}/code`];
46-
const pathToBeMatched = currentPath?.split("#")[0]?.slice(0, -1);
47-
return pathToBeMatched ? desiredPaths.includes(pathToBeMatched) : false;
51+
return sections.map((section) => ({
52+
title: section.label,
53+
items: section.links.map((link) => ({
54+
label: link.label,
55+
onSelect: () => router.push(link.path),
56+
selected: matchPaths(link.path),
57+
...(link.status && {
58+
badge: link.status !== "stable" ? <StatusBadge hasTitle status={link.status} /> : undefined,
59+
}),
60+
})),
61+
}));
4862
};
4963

64+
useEffect(() => {
65+
const paths = [...new Set(LinksSections.flatMap((s) => s.links.map((l) => l.path)))];
66+
const prefetchPaths = async () => {
67+
for (const path of paths) {
68+
await router.prefetch(path);
69+
}
70+
};
71+
void prefetchPaths();
72+
}, []);
73+
74+
// TODO: ADD FILTERING
75+
// TODO: ADD CATEGORIZATION
76+
77+
const sections = mapLinksToGroupItems(LinksSections);
78+
5079
return (
5180
<CacheProvider value={emotionCache}>
5281
<Head>
5382
<link rel="icon" type="image/png" sizes="32x32" href="/favicon.png" />
5483
</Head>
5584
<DxcApplicationLayout
56-
visibilityToggleLabel="Menu"
5785
sidenav={
58-
<DxcApplicationLayout.SideNav title={<SidenavLogo />}>
59-
<DxcApplicationLayout.SideNav.Section>
60-
<DxcTextInput
61-
placeholder="Search docs"
62-
value={filter}
63-
onChange={({ value }: { value: string }) => {
64-
setFilter(value);
65-
}}
66-
size="fillParent"
67-
clearable
68-
margin={{
69-
top: "large",
70-
bottom: "large",
71-
right: "medium",
72-
left: "medium",
73-
}}
74-
/>
75-
</DxcApplicationLayout.SideNav.Section>
76-
{filteredLinks?.map(({ label, links }) => (
86+
<DxcApplicationLayout.SideNav
87+
items={sections}
88+
// title={<SidenavLogo />}
89+
>
90+
{/* {filteredLinks?.map(({ label, links }) => (
7791
<DxcApplicationLayout.SideNav.Section key={label}>
7892
<DxcApplicationLayout.SideNav.Group title={label}>
7993
{links.map(({ label, path, status }) => (
@@ -91,7 +105,7 @@ export default function App({ Component, pageProps, emotionCache = clientSideEmo
91105
<DxcApplicationLayout.SideNav.Link href="https://github.com/dxc-technology/halstack-react" newWindow>
92106
GitHub
93107
</DxcApplicationLayout.SideNav.Link>
94-
</DxcApplicationLayout.SideNav.Section>
108+
</DxcApplicationLayout.SideNav.Section> */}
95109
</DxcApplicationLayout.SideNav>
96110
}
97111
>

apps/website/screens/components/application-layout/code/ApplicationLayoutCodePage.tsx

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,6 @@ const ApplicationLayoutPropsTable = () => (
7575
</td>
7676
<td>-</td>
7777
</tr>
78-
<tr>
79-
<td>visibilityToggleLabel</td>
80-
<td>
81-
<TableCode>string</TableCode>
82-
</td>
83-
<td>Text to be placed next to the hamburger button that toggles the visibility of the sidenav.</td>
84-
<td>-</td>
85-
</tr>
8678
</tbody>
8779
</DxcTable>
8880
);
@@ -100,16 +92,6 @@ const sections = [
10092
</DxcParagraph>
10193
),
10294
},
103-
{
104-
title: "DxcApplicationLayout.useResponsiveSidenavVisibility",
105-
content: (
106-
<DxcParagraph>
107-
Custom hook that returns a function to manually change the visibility of the sidenav in responsive mode. This
108-
can be very useful for cases where a custom sidenav is being used and some of its inner elements can close it
109-
(for example, a navigation link).
110-
</DxcParagraph>
111-
),
112-
},
11395
{
11496
title: "Examples",
11597
subSections: [

apps/website/screens/components/contextual-menu/code/ContextualMenuCodePage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const itemTypeString = `{
1212
icon?: string | SVG;
1313
label: string;
1414
onSelect?: () => void;
15-
selectedByDefault?: boolean;
15+
selected?: boolean;
1616
}`;
1717

1818
const groupItemTypeString = `{

packages/lib/src/contextual-menu/ContextualMenu.stories.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const groupItems = [
4242
icon: "bookmark",
4343
badge: <DxcBadge color="primary" label="Experimental" />,
4444
},
45-
{ label: "Selected Item 3", selectedByDefault: true },
45+
{ label: "Selected Item 3", selected: true },
4646
],
4747
},
4848
],
@@ -102,7 +102,7 @@ const sectionsWithScroll = [
102102
{ label: "Approved locations" },
103103
{ label: "Approved locations" },
104104
{ label: "Approved locations" },
105-
{ label: "Approved locations", selectedByDefault: true },
105+
{ label: "Approved locations", selected: true },
106106
],
107107
},
108108
];

packages/lib/src/contextual-menu/ContextualMenu.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ describe("Contextual menu component tests", () => {
4141
expect(actions[0]?.getAttribute("aria-pressed")).toBeTruthy();
4242
expect(getByRole("menu")).toBeTruthy();
4343
});
44-
test("Single — An item can appear as selected by default by using the attribute selectedByDefault", () => {
44+
test("Single — An item can appear as selected by default by using the attribute selected", () => {
4545
const test = [
4646
{
4747
label: "Tested item",
48-
selectedByDefault: true,
48+
selected: true,
4949
},
5050
];
5151
const { getByRole } = render(<DxcContextualMenu items={test} />);
@@ -92,7 +92,7 @@ describe("Contextual menu component tests", () => {
9292
const test = [
9393
{
9494
label: "Grouped item",
95-
items: [{ label: "Tested item", selectedByDefault: true }],
95+
items: [{ label: "Tested item", selected: true }],
9696
},
9797
];
9898
const { getByText, getAllByRole } = render(<DxcContextualMenu items={test} />);

packages/lib/src/contextual-menu/ContextualMenu.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,22 @@ export default function DxcContextualMenu({
3434
displayGroupLines = false,
3535
displayControlsAfter = false,
3636
responsiveView = false,
37+
allowNavigation = false,
3738
}: ContextualMenuPropsType) {
3839
const [firstUpdate, setFirstUpdate] = useState(true);
3940
const [selectedItemId, setSelectedItemId] = useState(-1);
4041
const contextualMenuRef = useRef<HTMLDivElement | null>(null);
4142
const itemsWithId = useMemo(() => addIdToItems(items), [items]);
4243
const contextValue = useMemo(
43-
() => ({ selectedItemId, setSelectedItemId, displayGroupLines, displayControlsAfter, responsiveView }),
44-
[selectedItemId, setSelectedItemId, displayGroupLines, displayControlsAfter, responsiveView]
44+
() => ({
45+
selectedItemId,
46+
setSelectedItemId,
47+
displayGroupLines,
48+
displayControlsAfter,
49+
responsiveView,
50+
allowNavigation,
51+
}),
52+
[selectedItemId, setSelectedItemId, displayGroupLines, displayControlsAfter, responsiveView, allowNavigation]
4553
);
4654

4755
useLayoutEffect(() => {

packages/lib/src/contextual-menu/ItemAction.tsx

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const Action = styled.button<{
2626
height: var(--height-s);
2727
cursor: pointer;
2828
overflow: hidden;
29+
text-decoration: none;
2930
3031
&:hover {
3132
background-color: ${({ selected }) =>
@@ -78,47 +79,53 @@ const Control = styled.span`
7879
`;
7980

8081
const ItemAction = memo(
81-
forwardRef<HTMLButtonElement, ItemActionProps>(({ badge, collapseIcon, depthLevel, icon, label, ...props }, ref) => {
82-
const [hasTooltip, setHasTooltip] = useState(false);
83-
const modifiedBadge = badge && cloneElement(badge, { size: "small" });
84-
const { displayControlsAfter, responsiveView, displayGroupLines } = useContext(ContextualMenuContext) ?? {};
82+
forwardRef<HTMLButtonElement, ItemActionProps>(
83+
({ badge, collapseIcon, depthLevel, icon, label, href, ...props }, ref) => {
84+
const [hasTooltip, setHasTooltip] = useState(false);
85+
const modifiedBadge = badge && cloneElement(badge, { size: "small" });
86+
const { displayControlsAfter, responsiveView, displayGroupLines, allowNavigation } =
87+
useContext(ContextualMenuContext) ?? {};
8588

86-
return (
87-
<TooltipWrapper condition={hasTooltip} label={label}>
88-
<Action
89-
ref={ref}
90-
depthLevel={depthLevel}
91-
displayGroupLines={!!displayGroupLines}
92-
responsiveView={responsiveView}
93-
{...props}
94-
>
95-
<Label>
96-
{!displayControlsAfter && <Control>{collapseIcon && <Icon>{collapseIcon}</Icon>}</Control>}
97-
<TooltipWrapper condition={responsiveView} label={label}>
98-
<Icon>{typeof icon === "string" ? <DxcIcon icon={icon} /> : icon}</Icon>
99-
</TooltipWrapper>
89+
return (
90+
<TooltipWrapper condition={hasTooltip} label={label}>
91+
<Action
92+
as={allowNavigation && href ? "a" : "button"}
93+
role={allowNavigation && href ? "link" : "button"}
94+
ref={ref}
95+
depthLevel={depthLevel}
96+
displayGroupLines={!!displayGroupLines}
97+
responsiveView={responsiveView}
98+
{...(allowNavigation && href && { href })}
99+
{...props}
100+
>
101+
<Label>
102+
{!displayControlsAfter && <Control>{collapseIcon && <Icon>{collapseIcon}</Icon>}</Control>}
103+
<TooltipWrapper condition={responsiveView} label={label}>
104+
<Icon>{typeof icon === "string" ? <DxcIcon icon={icon} /> : icon}</Icon>
105+
</TooltipWrapper>
106+
{!responsiveView && (
107+
<Text
108+
selected={props.selected}
109+
onMouseEnter={(event: MouseEvent<HTMLSpanElement>) => {
110+
const text = event.currentTarget;
111+
setHasTooltip(text.scrollWidth > text.clientWidth);
112+
}}
113+
>
114+
{label}
115+
</Text>
116+
)}
117+
</Label>
100118
{!responsiveView && (
101-
<Text
102-
selected={props.selected}
103-
onMouseEnter={(event: MouseEvent<HTMLSpanElement>) => {
104-
const text = event.currentTarget;
105-
setHasTooltip(text.scrollWidth > text.clientWidth);
106-
}}
107-
>
108-
{label}
109-
</Text>
119+
<Control>
120+
{modifiedBadge}
121+
{displayControlsAfter && collapseIcon && <Icon>{collapseIcon}</Icon>}
122+
</Control>
110123
)}
111-
</Label>
112-
{!responsiveView && (
113-
<Control>
114-
{modifiedBadge}
115-
{displayControlsAfter && collapseIcon && <Icon>{collapseIcon}</Icon>}
116-
</Control>
117-
)}
118-
</Action>
119-
</TooltipWrapper>
120-
);
121-
})
124+
</Action>
125+
</TooltipWrapper>
126+
);
127+
}
128+
)
122129
);
123130

124131
ItemAction.displayName = "ItemAction";

packages/lib/src/contextual-menu/SingleItem.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import ItemAction from "./ItemAction";
33
import { SingleItemProps } from "./types";
44
import ContextualMenuContext from "./ContextualMenuContext";
55

6-
export default function SingleItem({ id, onSelect, selectedByDefault = false, ...props }: SingleItemProps) {
6+
export default function SingleItem({ id, onSelect, selected = false, ...props }: SingleItemProps) {
77
const { selectedItemId, setSelectedItemId } = useContext(ContextualMenuContext) ?? {};
88

99
const handleClick = () => {
@@ -12,18 +12,16 @@ export default function SingleItem({ id, onSelect, selectedByDefault = false, ..
1212
};
1313

1414
useEffect(() => {
15-
if (selectedItemId === -1 && selectedByDefault) {
15+
if (selectedItemId === -1 && selected) {
1616
setSelectedItemId?.(id);
1717
}
18-
}, [selectedItemId, selectedByDefault, id]);
18+
}, [selectedItemId, selected, id]);
1919

2020
return (
2121
<ItemAction
22-
aria-pressed={selectedItemId === -1 ? selectedByDefault : selectedItemId === id}
22+
aria-pressed={selectedItemId === -1 ? selected : selectedItemId === id}
2323
onClick={handleClick}
24-
selected={
25-
selectedItemId != null && (selectedItemId === -1 ? (selectedByDefault ?? false) : selectedItemId === id)
26-
}
24+
selected={selectedItemId != null && (selectedItemId === -1 ? (selected ?? false) : selectedItemId === id)}
2725
{...props}
2826
/>
2927
);

0 commit comments

Comments
 (0)