Skip to content

Commit 28453e0

Browse files
committed
render category custom props as data attributes
1 parent 439fcac commit 28453e0

File tree

1 file changed

+212
-0
lines changed
  • src/theme/DocSidebarItem/Category

1 file changed

+212
-0
lines changed
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import Link from '@docusaurus/Link';
2+
import {
3+
isActiveSidebarItem,
4+
findFirstSidebarItemLink,
5+
useDocSidebarItemsExpandedState,
6+
} from '@docusaurus/plugin-content-docs/client';
7+
import {
8+
ThemeClassNames,
9+
useThemeConfig,
10+
usePrevious,
11+
Collapsible,
12+
useCollapsible,
13+
} from '@docusaurus/theme-common';
14+
import { isSamePath } from '@docusaurus/theme-common/internal';
15+
import { translate } from '@docusaurus/Translate';
16+
import useIsBrowser from '@docusaurus/useIsBrowser';
17+
import DocSidebarItems from '@theme/DocSidebarItems';
18+
import clsx from 'clsx';
19+
import React, { useEffect, useMemo } from 'react';
20+
21+
// If we navigate to a category and it becomes active, it should automatically
22+
// expand itself
23+
function useAutoExpandActiveCategory({ isActive, collapsed, updateCollapsed }) {
24+
const wasActive = usePrevious(isActive);
25+
useEffect(() => {
26+
const justBecameActive = isActive && !wasActive;
27+
if (justBecameActive && collapsed) {
28+
updateCollapsed(false);
29+
}
30+
}, [isActive, wasActive, collapsed, updateCollapsed]);
31+
}
32+
33+
/**
34+
* When a collapsible category has no link, we still link it to its first child
35+
* during SSR as a temporary fallback. This allows to be able to navigate inside
36+
* the category even when JS fails to load, is delayed or simply disabled
37+
* React hydration becomes an optional progressive enhancement
38+
* see https://github.com/facebookincubator/infima/issues/36#issuecomment-772543188
39+
* see https://github.com/facebook/docusaurus/issues/3030
40+
*/
41+
function useCategoryHrefWithSSRFallback(item) {
42+
const isBrowser = useIsBrowser();
43+
return useMemo(() => {
44+
if (item.href && !item.linkUnlisted) {
45+
return item.href;
46+
}
47+
// In these cases, it's not necessary to render a fallback
48+
// We skip the "findFirstCategoryLink" computation
49+
if (isBrowser || !item.collapsible) {
50+
return undefined;
51+
}
52+
return findFirstSidebarItemLink(item);
53+
}, [item, isBrowser]);
54+
}
55+
56+
function CollapseButton({ collapsed, categoryLabel, onClick }) {
57+
return (
58+
<button
59+
aria-label={
60+
collapsed
61+
? translate(
62+
{
63+
id: 'theme.DocSidebarItem.expandCategoryAriaLabel',
64+
message: 'Expand sidebar category \'{label}\'',
65+
description: 'The ARIA label to expand the sidebar category',
66+
},
67+
{ label: categoryLabel },
68+
)
69+
: translate(
70+
{
71+
id: 'theme.DocSidebarItem.collapseCategoryAriaLabel',
72+
message: 'Collapse sidebar category \'{label}\'',
73+
description: 'The ARIA label to collapse the sidebar category',
74+
},
75+
{ label: categoryLabel },
76+
)
77+
}
78+
aria-expanded={!collapsed}
79+
type="button"
80+
className="clean-btn menu__caret"
81+
onClick={onClick}
82+
/>
83+
);
84+
}
85+
86+
export default function DocSidebarItemCategory({ item, onItemClick, activePath, level, index, ...props }) {
87+
const { items, label, collapsible, className, href } = item;
88+
const {
89+
docs: {
90+
sidebar: { autoCollapseCategories },
91+
},
92+
} = useThemeConfig();
93+
const hrefWithSSRFallback = useCategoryHrefWithSSRFallback(item);
94+
const isActive = isActiveSidebarItem(item, activePath);
95+
const isCurrentPage = isSamePath(href, activePath);
96+
const {
97+
collapsed,
98+
setCollapsed,
99+
} = useCollapsible({
100+
// Active categories are always initialized as expanded. The default
101+
// (`item.collapsed`) is only used for non-active categories.
102+
initialState: () => {
103+
if (!collapsible) {
104+
return false;
105+
}
106+
return isActive ? false : item.collapsed;
107+
},
108+
});
109+
const {
110+
expandedItem,
111+
setExpandedItem,
112+
} = useDocSidebarItemsExpandedState();
113+
// Use this instead of `setCollapsed`, because it is also reactive
114+
const updateCollapsed = (toCollapsed = !collapsed) => {
115+
setExpandedItem(toCollapsed ? null : index);
116+
setCollapsed(toCollapsed);
117+
};
118+
useAutoExpandActiveCategory({
119+
isActive,
120+
collapsed,
121+
updateCollapsed,
122+
});
123+
useEffect(() => {
124+
if (
125+
collapsible
126+
&& expandedItem != null
127+
&& expandedItem !== index
128+
&& autoCollapseCategories
129+
) {
130+
setCollapsed(true);
131+
}
132+
}, [collapsible, expandedItem, index, setCollapsed, autoCollapseCategories]);
133+
134+
if (item.customProps) {
135+
for (const key of Object.keys(item.customProps)) {
136+
props[`data-${key}`] = item.customProps[key];
137+
}
138+
}
139+
140+
console.log(item);
141+
142+
return (
143+
<li
144+
className={clsx(
145+
ThemeClassNames.docs.docSidebarItemCategory,
146+
ThemeClassNames.docs.docSidebarItemCategoryLevel(level),
147+
'menu__list-item',
148+
{
149+
'menu__list-item--collapsed': collapsed,
150+
},
151+
className,
152+
)}>
153+
<div
154+
className={clsx('menu__list-item-collapsible', {
155+
'menu__list-item-collapsible--active': isCurrentPage,
156+
})}>
157+
<Link
158+
className={clsx('menu__link', {
159+
'menu__link--sublist': collapsible,
160+
'menu__link--sublist-caret': !href && collapsible,
161+
'menu__link--active': isActive,
162+
})}
163+
onClick={
164+
collapsible
165+
? (e) => {
166+
onItemClick?.(item);
167+
if (href) {
168+
updateCollapsed(false);
169+
} else {
170+
e.preventDefault();
171+
updateCollapsed();
172+
}
173+
}
174+
: () => {
175+
onItemClick?.(item);
176+
}
177+
}
178+
aria-current={isCurrentPage ? 'page' : undefined}
179+
role={collapsible && !href ? 'button' : undefined}
180+
aria-expanded={collapsible && !href ? !collapsed : undefined}
181+
href={collapsible ? hrefWithSSRFallback ?? '#' : hrefWithSSRFallback}
182+
{...props}>
183+
{label}
184+
</Link>
185+
{href && collapsible && (
186+
<CollapseButton
187+
collapsed={collapsed}
188+
categoryLabel={label}
189+
onClick={(e) => {
190+
e.preventDefault();
191+
updateCollapsed();
192+
}}
193+
/>
194+
)}
195+
</div>
196+
197+
<Collapsible
198+
lazy
199+
as="ul"
200+
className="menu__list"
201+
collapsed={collapsed}>
202+
<DocSidebarItems
203+
items={items}
204+
tabIndex={collapsed ? -1 : 0}
205+
onItemClick={onItemClick}
206+
activePath={activePath}
207+
level={level + 1}
208+
/>
209+
</Collapsible>
210+
</li>
211+
);
212+
}

0 commit comments

Comments
 (0)