mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-22 13:37:05 +02:00
refactor(theme): move LayoutProviders to Layout/Provider; composeProviders util (#7676)
Co-authored-by: Joshua Chen <sidachen2003@gmail.com>
This commit is contained in:
parent
90a8ca387e
commit
afc08eef4f
7 changed files with 79 additions and 44 deletions
|
@ -596,14 +596,14 @@ declare module '@theme/Layout' {
|
||||||
export default function Layout(props: Props): JSX.Element;
|
export default function Layout(props: Props): JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/LayoutProviders' {
|
declare module '@theme/Layout/Provider' {
|
||||||
import type {ReactNode} from 'react';
|
import type {ReactNode} from 'react';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly children: ReactNode;
|
readonly children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function LayoutProviders(props: Props): JSX.Element;
|
export default function LayoutProvider(props: Props): JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/SearchMetadata' {
|
declare module '@theme/SearchMetadata' {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {composeProviders} from '@docusaurus/theme-common';
|
||||||
|
import {
|
||||||
|
ColorModeProvider,
|
||||||
|
TabGroupChoiceProvider,
|
||||||
|
AnnouncementBarProvider,
|
||||||
|
DocsPreferredVersionContextProvider,
|
||||||
|
ScrollControllerProvider,
|
||||||
|
NavbarProvider,
|
||||||
|
PluginHtmlClassNameProvider,
|
||||||
|
} from '@docusaurus/theme-common/internal';
|
||||||
|
import type {Props} from '@theme/Layout/Provider';
|
||||||
|
|
||||||
|
const Provider = composeProviders([
|
||||||
|
ColorModeProvider,
|
||||||
|
AnnouncementBarProvider,
|
||||||
|
TabGroupChoiceProvider,
|
||||||
|
ScrollControllerProvider,
|
||||||
|
DocsPreferredVersionContextProvider,
|
||||||
|
PluginHtmlClassNameProvider,
|
||||||
|
NavbarProvider,
|
||||||
|
]);
|
||||||
|
|
||||||
|
export default function LayoutProvider({children}: Props): JSX.Element {
|
||||||
|
return <Provider>{children}</Provider>;
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ import SkipToContent from '@theme/SkipToContent';
|
||||||
import AnnouncementBar from '@theme/AnnouncementBar';
|
import AnnouncementBar from '@theme/AnnouncementBar';
|
||||||
import Navbar from '@theme/Navbar';
|
import Navbar from '@theme/Navbar';
|
||||||
import Footer from '@theme/Footer';
|
import Footer from '@theme/Footer';
|
||||||
import LayoutProviders from '@theme/LayoutProviders';
|
import LayoutProvider from '@theme/Layout/Provider';
|
||||||
import ErrorPageContent from '@theme/ErrorPageContent';
|
import ErrorPageContent from '@theme/ErrorPageContent';
|
||||||
import type {Props} from '@theme/Layout';
|
import type {Props} from '@theme/Layout';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
@ -32,7 +32,7 @@ export default function Layout(props: Props): JSX.Element {
|
||||||
useKeyboardNavigation();
|
useKeyboardNavigation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutProviders>
|
<LayoutProvider>
|
||||||
<PageMetadata title={title} description={description} />
|
<PageMetadata title={title} description={description} />
|
||||||
|
|
||||||
<SkipToContent />
|
<SkipToContent />
|
||||||
|
@ -53,6 +53,6 @@ export default function Layout(props: Props): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!noFooter && <Footer />}
|
{!noFooter && <Footer />}
|
||||||
</LayoutProviders>
|
</LayoutProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
ColorModeProvider,
|
|
||||||
TabGroupChoiceProvider,
|
|
||||||
AnnouncementBarProvider,
|
|
||||||
DocsPreferredVersionContextProvider,
|
|
||||||
ScrollControllerProvider,
|
|
||||||
NavbarProvider,
|
|
||||||
PluginHtmlClassNameProvider,
|
|
||||||
} from '@docusaurus/theme-common/internal';
|
|
||||||
import type {Props} from '@theme/LayoutProviders';
|
|
||||||
|
|
||||||
export default function LayoutProviders({children}: Props): JSX.Element {
|
|
||||||
return (
|
|
||||||
<ColorModeProvider>
|
|
||||||
<AnnouncementBarProvider>
|
|
||||||
<TabGroupChoiceProvider>
|
|
||||||
<ScrollControllerProvider>
|
|
||||||
<DocsPreferredVersionContextProvider>
|
|
||||||
<PluginHtmlClassNameProvider>
|
|
||||||
<NavbarProvider>{children}</NavbarProvider>
|
|
||||||
</PluginHtmlClassNameProvider>
|
|
||||||
</DocsPreferredVersionContextProvider>
|
|
||||||
</ScrollControllerProvider>
|
|
||||||
</TabGroupChoiceProvider>
|
|
||||||
</AnnouncementBarProvider>
|
|
||||||
</ColorModeProvider>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -175,7 +175,7 @@ function DocsPreferredVersionContextProviderUnsafe({
|
||||||
export function DocsPreferredVersionContextProvider({
|
export function DocsPreferredVersionContextProvider({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children: JSX.Element;
|
children: ReactNode;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
if (isDocsPluginEnabled) {
|
if (isDocsPluginEnabled) {
|
||||||
return (
|
return (
|
||||||
|
@ -184,7 +184,7 @@ export function DocsPreferredVersionContextProvider({
|
||||||
</DocsPreferredVersionContextProviderUnsafe>
|
</DocsPreferredVersionContextProviderUnsafe>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return children;
|
return <>{children}</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useDocsPreferredVersionContext(): ContextValue {
|
function useDocsPreferredVersionContext(): ContextValue {
|
||||||
|
|
|
@ -40,6 +40,7 @@ export {
|
||||||
useIsomorphicLayoutEffect,
|
useIsomorphicLayoutEffect,
|
||||||
useEvent,
|
useEvent,
|
||||||
usePrevious,
|
usePrevious,
|
||||||
|
composeProviders,
|
||||||
ReactContextError,
|
ReactContextError,
|
||||||
} from './utils/reactUtils';
|
} from './utils/reactUtils';
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,15 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {useCallback, useEffect, useLayoutEffect, useMemo, useRef} from 'react';
|
import React, {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useLayoutEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
type ComponentType,
|
||||||
|
type ReactNode,
|
||||||
|
} from 'react';
|
||||||
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,3 +98,32 @@ export function useShallowMemoObject<O extends object>(obj: O): O {
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
return useMemo(() => obj, deps.flat());
|
return useMemo(() => obj, deps.flat());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SimpleProvider = ComponentType<{children: ReactNode}>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a single React provider from an array of existing providers
|
||||||
|
* assuming providers only take "children" as props.
|
||||||
|
*
|
||||||
|
* Prevents the annoying React element nesting
|
||||||
|
* Example here: https://getfrontend.tips/compose-multiple-react-providers/
|
||||||
|
*
|
||||||
|
* The order matters:
|
||||||
|
* - The first provider is at the top of the tree.
|
||||||
|
* - The last provider is the most nested one
|
||||||
|
*
|
||||||
|
* @param providers array of providers to compose
|
||||||
|
*/
|
||||||
|
export function composeProviders(providers: SimpleProvider[]): SimpleProvider {
|
||||||
|
// Creates a single React component: it's cheaper to compose JSX elements
|
||||||
|
return ({children}) => (
|
||||||
|
<>
|
||||||
|
{providers.reduceRight(
|
||||||
|
(element, CurrentProvider) => (
|
||||||
|
<CurrentProvider>{element}</CurrentProvider>
|
||||||
|
),
|
||||||
|
children,
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue