mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-14 08:42:31 +02:00
refactor: split and cleanup theme/DocPage (#7006)
This commit is contained in:
parent
2964e6f65d
commit
1b974e8b1b
10 changed files with 299 additions and 163 deletions
|
@ -13,19 +13,24 @@ import type {PropSidebar} from '@docusaurus/plugin-content-docs';
|
|||
describe('useDocsSidebar', () => {
|
||||
it('throws if context provider is missing', () => {
|
||||
expect(
|
||||
() => renderHook(() => useDocsSidebar()).result.current,
|
||||
() => renderHook(() => useDocsSidebar()).result.current?.items,
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Hook useDocsSidebar is called outside the <DocsSidebarProvider>. "`,
|
||||
);
|
||||
});
|
||||
|
||||
it('reads value from context provider', () => {
|
||||
const sidebar: PropSidebar = [];
|
||||
const name = 'mySidebarName';
|
||||
const items: PropSidebar = [];
|
||||
const {result} = renderHook(() => useDocsSidebar(), {
|
||||
wrapper: ({children}) => (
|
||||
<DocsSidebarProvider sidebar={sidebar}>{children}</DocsSidebarProvider>
|
||||
<DocsSidebarProvider name={name} items={items}>
|
||||
{children}
|
||||
</DocsSidebarProvider>
|
||||
),
|
||||
});
|
||||
expect(result.current).toBe(sidebar);
|
||||
expect(result.current).toBeDefined();
|
||||
expect(result.current!.name).toBe(name);
|
||||
expect(result.current!.items).toBe(items);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React, {type ReactNode, useContext} from 'react';
|
||||
import React, {useMemo, useContext, type ReactNode} from 'react';
|
||||
import type {PropSidebar} from '@docusaurus/plugin-content-docs';
|
||||
import {ReactContextError} from '../utils/reactUtils';
|
||||
|
||||
|
@ -13,30 +13,44 @@ import {ReactContextError} from '../utils/reactUtils';
|
|||
// Inspired by https://github.com/jamiebuilds/unstated-next/blob/master/src/unstated-next.tsx
|
||||
const EmptyContext: unique symbol = Symbol('EmptyContext');
|
||||
|
||||
const Context = React.createContext<PropSidebar | null | typeof EmptyContext>(
|
||||
EmptyContext,
|
||||
);
|
||||
type SidebarContextValue = {name: string; items: PropSidebar};
|
||||
|
||||
const Context = React.createContext<
|
||||
SidebarContextValue | null | typeof EmptyContext
|
||||
>(EmptyContext);
|
||||
|
||||
/**
|
||||
* Provide the current sidebar to your children.
|
||||
*/
|
||||
export function DocsSidebarProvider({
|
||||
children,
|
||||
sidebar,
|
||||
name,
|
||||
items,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
sidebar: PropSidebar | null;
|
||||
name: string | undefined;
|
||||
items: PropSidebar | undefined;
|
||||
}): JSX.Element {
|
||||
return <Context.Provider value={sidebar}>{children}</Context.Provider>;
|
||||
const stableValue: SidebarContextValue | null = useMemo(
|
||||
() =>
|
||||
name && items
|
||||
? {
|
||||
name,
|
||||
items,
|
||||
}
|
||||
: null,
|
||||
[name, items],
|
||||
);
|
||||
return <Context.Provider value={stableValue}>{children}</Context.Provider>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sidebar that's currently displayed, or `null` if there isn't one
|
||||
* Gets the sidebar data that's currently displayed, or `null` if there isn't one
|
||||
*/
|
||||
export function useDocsSidebar(): PropSidebar | null {
|
||||
const sidebar = useContext(Context);
|
||||
if (sidebar === EmptyContext) {
|
||||
export function useDocsSidebar(): SidebarContextValue | null {
|
||||
const value = useContext(Context);
|
||||
if (value === EmptyContext) {
|
||||
throw new ReactContextError('DocsSidebarProvider');
|
||||
}
|
||||
return sidebar;
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -307,7 +307,7 @@ describe('useSidebarBreadcrumbs', () => {
|
|||
},
|
||||
},
|
||||
}}>
|
||||
<DocsSidebarProvider sidebar={sidebar}>
|
||||
<DocsSidebarProvider name="sidebarName" items={sidebar}>
|
||||
{children}
|
||||
</DocsSidebarProvider>
|
||||
</Context.Provider>
|
||||
|
@ -430,7 +430,7 @@ describe('useCurrentSidebarCategory', () => {
|
|||
(sidebar?: PropSidebar) => (location: string) =>
|
||||
renderHook(() => useCurrentSidebarCategory(), {
|
||||
wrapper: ({children}) => (
|
||||
<DocsSidebarProvider sidebar={sidebar}>
|
||||
<DocsSidebarProvider name="sidebarName" items={sidebar}>
|
||||
<StaticRouter location={location}>{children}</StaticRouter>
|
||||
</DocsSidebarProvider>
|
||||
),
|
||||
|
|
|
@ -105,7 +105,7 @@ export function useCurrentSidebarCategory(): PropSidebarItemCategory {
|
|||
if (!sidebar) {
|
||||
throw new Error('Unexpected: cant find current sidebar in context');
|
||||
}
|
||||
const category = findSidebarCategory(sidebar, (item) =>
|
||||
const category = findSidebarCategory(sidebar.items, (item) =>
|
||||
isSamePath(item.href, pathname),
|
||||
);
|
||||
if (!category) {
|
||||
|
@ -174,7 +174,7 @@ export function useSidebarBreadcrumbs(): PropSidebarBreadcrumbsItem[] | null {
|
|||
return false;
|
||||
}
|
||||
|
||||
extract(sidebar);
|
||||
extract(sidebar.items);
|
||||
|
||||
return breadcrumbs.reverse();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue