mirror of
https://github.com/facebook/docusaurus.git
synced 2025-07-26 04:57:50 +02:00
refactor: move @theme/hooks to @docusaurus/theme-common (#6289)
This commit is contained in:
parent
024f2bf49b
commit
f87a3ead46
36 changed files with 245 additions and 401 deletions
|
@ -215,86 +215,6 @@ declare module '@theme/Heading' {
|
||||||
export default function Heading(props: Props): JSX.Element;
|
export default function Heading(props: Props): JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/hooks/useHideableNavbar' {
|
|
||||||
export type useHideableNavbarReturns = {
|
|
||||||
readonly navbarRef: (node: HTMLElement | null) => void;
|
|
||||||
readonly isNavbarVisible: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const useHideableNavbar: (hideOnScroll: boolean) => useHideableNavbarReturns;
|
|
||||||
export default useHideableNavbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/hooks/useLockBodyScroll' {
|
|
||||||
const useLockBodyScroll: (lock?: boolean) => void;
|
|
||||||
export default useLockBodyScroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/hooks/usePrismTheme' {
|
|
||||||
import type defaultTheme from 'prism-react-renderer/themes/palenight';
|
|
||||||
|
|
||||||
const usePrismTheme: () => typeof defaultTheme;
|
|
||||||
export default usePrismTheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/hooks/useTabGroupChoice' {
|
|
||||||
export type useTabGroupChoiceReturns = {
|
|
||||||
readonly tabGroupChoices: {readonly [groupId: string]: string};
|
|
||||||
readonly setTabGroupChoices: (groupId: string, newChoice: string) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const useTabGroupChoice: () => useTabGroupChoiceReturns;
|
|
||||||
export default useTabGroupChoice;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/hooks/useTheme' {
|
|
||||||
export type useThemeReturns = {
|
|
||||||
readonly isDarkTheme: boolean;
|
|
||||||
readonly setLightTheme: () => void;
|
|
||||||
readonly setDarkTheme: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const useTheme: () => useThemeReturns;
|
|
||||||
export default useTheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/hooks/useThemeContext' {
|
|
||||||
export type ThemeContextProps = {
|
|
||||||
isDarkTheme: boolean;
|
|
||||||
setLightTheme: () => void;
|
|
||||||
setDarkTheme: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function useThemeContext(): ThemeContextProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/hooks/useUserPreferencesContext' {
|
|
||||||
export type UserPreferencesContextProps = {
|
|
||||||
tabGroupChoices: {readonly [groupId: string]: string};
|
|
||||||
setTabGroupChoices: (groupId: string, newChoice: string) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function useUserPreferencesContext(): UserPreferencesContextProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/hooks/useWindowSize' {
|
|
||||||
export const windowSizes: {
|
|
||||||
desktop: 'desktop';
|
|
||||||
mobile: 'mobile';
|
|
||||||
ssr: 'ssr';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WindowSize = keyof typeof windowSizes;
|
|
||||||
|
|
||||||
export default function useWindowSize(): WindowSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/hooks/useKeyboardNavigation' {
|
|
||||||
const useKeyboardNavigation: () => void;
|
|
||||||
|
|
||||||
export default useKeyboardNavigation;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/Layout' {
|
declare module '@theme/Layout' {
|
||||||
import type {ReactNode} from 'react';
|
import type {ReactNode} from 'react';
|
||||||
|
|
||||||
|
@ -314,8 +234,7 @@ declare module '@theme/Layout' {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Layout: (props: Props) => JSX.Element;
|
export default function Layout(props: Props): JSX.Element;
|
||||||
export default Layout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/LayoutHead' {
|
declare module '@theme/LayoutHead' {
|
||||||
|
@ -323,8 +242,17 @@ declare module '@theme/LayoutHead' {
|
||||||
|
|
||||||
export interface Props extends Omit<LayoutProps, 'children'> {}
|
export interface Props extends Omit<LayoutProps, 'children'> {}
|
||||||
|
|
||||||
const LayoutHead: (props: Props) => JSX.Element;
|
export default function LayoutHead(props: Props): JSX.Element;
|
||||||
export default LayoutHead;
|
}
|
||||||
|
|
||||||
|
declare module '@theme/LayoutProviders' {
|
||||||
|
import type {ReactNode} from 'react';
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
readonly children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function LayoutProviders(props: Props): JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/SearchMetadata' {
|
declare module '@theme/SearchMetadata' {
|
||||||
|
@ -621,17 +549,6 @@ declare module '@theme/Details' {
|
||||||
export default Details;
|
export default Details;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/ThemeProvider' {
|
|
||||||
import type {ReactNode} from 'react';
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
readonly children: ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ThemeProvider: (props: Props) => JSX.Element;
|
|
||||||
export default ThemeProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/TOCItems' {
|
declare module '@theme/TOCItems' {
|
||||||
import type {TOCItem} from '@docusaurus/types';
|
import type {TOCItem} from '@docusaurus/types';
|
||||||
|
|
||||||
|
@ -712,46 +629,6 @@ declare module '@theme/Toggle' {
|
||||||
export default Toggle;
|
export default Toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/UserPreferencesProvider' {
|
|
||||||
import type {ReactNode} from 'react';
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
readonly children: ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const UserPreferencesProvider: (props: Props) => JSX.Element;
|
|
||||||
export default UserPreferencesProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/LayoutProviders' {
|
|
||||||
import type {ReactNode} from 'react';
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
readonly children: ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LayoutProviders: (props: Props) => JSX.Element;
|
|
||||||
export default LayoutProviders;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/ThemeContext' {
|
|
||||||
import type {Context} from 'react';
|
|
||||||
import type {ThemeContextProps} from '@theme/hooks/useThemeContext';
|
|
||||||
|
|
||||||
const ThemeContext: Context<ThemeContextProps | undefined>;
|
|
||||||
export default ThemeContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/UserPreferencesContext' {
|
|
||||||
import type {Context} from 'react';
|
|
||||||
import type {UserPreferencesContextProps} from '@theme/hooks/useUserPreferencesContext';
|
|
||||||
|
|
||||||
const UserPreferencesContext: Context<
|
|
||||||
UserPreferencesContextProps | undefined
|
|
||||||
>;
|
|
||||||
export default UserPreferencesContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/Logo' {
|
declare module '@theme/Logo' {
|
||||||
import type {ComponentProps} from 'react';
|
import type {ComponentProps} from 'react';
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ import {
|
||||||
parseLanguage,
|
parseLanguage,
|
||||||
parseLines,
|
parseLines,
|
||||||
ThemeClassNames,
|
ThemeClassNames,
|
||||||
|
usePrismTheme,
|
||||||
} from '@docusaurus/theme-common';
|
} from '@docusaurus/theme-common';
|
||||||
import usePrismTheme from '@theme/hooks/usePrismTheme';
|
|
||||||
import type {Props} from '@theme/CodeBlock';
|
import type {Props} from '@theme/CodeBlock';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import useWindowSize from '@theme/hooks/useWindowSize';
|
|
||||||
import DocPaginator from '@theme/DocPaginator';
|
import DocPaginator from '@theme/DocPaginator';
|
||||||
import DocVersionBanner from '@theme/DocVersionBanner';
|
import DocVersionBanner from '@theme/DocVersionBanner';
|
||||||
import DocVersionBadge from '@theme/DocVersionBadge';
|
import DocVersionBadge from '@theme/DocVersionBadge';
|
||||||
|
@ -18,7 +17,7 @@ import TOC from '@theme/TOC';
|
||||||
import TOCCollapsible from '@theme/TOCCollapsible';
|
import TOCCollapsible from '@theme/TOCCollapsible';
|
||||||
import Heading from '@theme/Heading';
|
import Heading from '@theme/Heading';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
import {ThemeClassNames} from '@docusaurus/theme-common';
|
import {ThemeClassNames, useWindowSize} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
export default function DocItem(props: Props): JSX.Element {
|
export default function DocItem(props: Props): JSX.Element {
|
||||||
const {content: DocContent} = props;
|
const {content: DocContent} = props;
|
||||||
|
|
|
@ -14,8 +14,8 @@ import {
|
||||||
type MobileSecondaryMenuComponent,
|
type MobileSecondaryMenuComponent,
|
||||||
ThemeClassNames,
|
ThemeClassNames,
|
||||||
useScrollPosition,
|
useScrollPosition,
|
||||||
|
useWindowSize,
|
||||||
} from '@docusaurus/theme-common';
|
} from '@docusaurus/theme-common';
|
||||||
import useWindowSize from '@theme/hooks/useWindowSize';
|
|
||||||
import Logo from '@theme/Logo';
|
import Logo from '@theme/Logo';
|
||||||
import IconArrow from '@theme/IconArrow';
|
import IconArrow from '@theme/IconArrow';
|
||||||
import {translate} from '@docusaurus/Translate';
|
import {translate} from '@docusaurus/Translate';
|
||||||
|
|
|
@ -15,8 +15,7 @@ import Footer from '@theme/Footer';
|
||||||
import LayoutProviders from '@theme/LayoutProviders';
|
import LayoutProviders from '@theme/LayoutProviders';
|
||||||
import LayoutHead from '@theme/LayoutHead';
|
import LayoutHead from '@theme/LayoutHead';
|
||||||
import type {Props} from '@theme/Layout';
|
import type {Props} from '@theme/Layout';
|
||||||
import useKeyboardNavigation from '@theme/hooks/useKeyboardNavigation';
|
import {ThemeClassNames, useKeyboardNavigation} from '@docusaurus/theme-common';
|
||||||
import {ThemeClassNames} from '@docusaurus/theme-common';
|
|
||||||
import ErrorPageContent from '@theme/ErrorPageContent';
|
import ErrorPageContent from '@theme/ErrorPageContent';
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ThemeProvider from '@theme/ThemeProvider';
|
|
||||||
import UserPreferencesProvider from '@theme/UserPreferencesProvider';
|
|
||||||
import {
|
import {
|
||||||
|
ColorModeProvider,
|
||||||
|
TabGroupChoiceProvider,
|
||||||
AnnouncementBarProvider,
|
AnnouncementBarProvider,
|
||||||
DocsPreferredVersionContextProvider,
|
DocsPreferredVersionContextProvider,
|
||||||
MobileSecondaryMenuProvider,
|
MobileSecondaryMenuProvider,
|
||||||
|
@ -18,9 +18,9 @@ import type {Props} from '@theme/LayoutProviders';
|
||||||
|
|
||||||
export default function LayoutProviders({children}: Props): JSX.Element {
|
export default function LayoutProviders({children}: Props): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider>
|
<ColorModeProvider>
|
||||||
<AnnouncementBarProvider>
|
<AnnouncementBarProvider>
|
||||||
<UserPreferencesProvider>
|
<TabGroupChoiceProvider>
|
||||||
<ScrollControllerProvider>
|
<ScrollControllerProvider>
|
||||||
<DocsPreferredVersionContextProvider>
|
<DocsPreferredVersionContextProvider>
|
||||||
<MobileSecondaryMenuProvider>
|
<MobileSecondaryMenuProvider>
|
||||||
|
@ -28,8 +28,8 @@ export default function LayoutProviders({children}: Props): JSX.Element {
|
||||||
</MobileSecondaryMenuProvider>
|
</MobileSecondaryMenuProvider>
|
||||||
</DocsPreferredVersionContextProvider>
|
</DocsPreferredVersionContextProvider>
|
||||||
</ScrollControllerProvider>
|
</ScrollControllerProvider>
|
||||||
</UserPreferencesProvider>
|
</TabGroupChoiceProvider>
|
||||||
</AnnouncementBarProvider>
|
</AnnouncementBarProvider>
|
||||||
</ThemeProvider>
|
</ColorModeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,16 @@ import clsx from 'clsx';
|
||||||
import Translate from '@docusaurus/Translate';
|
import Translate from '@docusaurus/Translate';
|
||||||
import SearchBar from '@theme/SearchBar';
|
import SearchBar from '@theme/SearchBar';
|
||||||
import Toggle from '@theme/Toggle';
|
import Toggle from '@theme/Toggle';
|
||||||
import useThemeContext from '@theme/hooks/useThemeContext';
|
|
||||||
import {
|
import {
|
||||||
useThemeConfig,
|
useThemeConfig,
|
||||||
useMobileSecondaryMenuRenderer,
|
useMobileSecondaryMenuRenderer,
|
||||||
usePrevious,
|
usePrevious,
|
||||||
useHistoryPopHandler,
|
useHistoryPopHandler,
|
||||||
|
useHideableNavbar,
|
||||||
|
useLockBodyScroll,
|
||||||
|
useWindowSize,
|
||||||
|
useColorMode,
|
||||||
} from '@docusaurus/theme-common';
|
} from '@docusaurus/theme-common';
|
||||||
import useHideableNavbar from '@theme/hooks/useHideableNavbar';
|
|
||||||
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
|
|
||||||
import useWindowSize from '@theme/hooks/useWindowSize';
|
|
||||||
import {useActivePlugin} from '@docusaurus/plugin-content-docs/client';
|
import {useActivePlugin} from '@docusaurus/plugin-content-docs/client';
|
||||||
import NavbarItem, {type Props as NavbarItemConfig} from '@theme/NavbarItem';
|
import NavbarItem, {type Props as NavbarItemConfig} from '@theme/NavbarItem';
|
||||||
import Logo from '@theme/Logo';
|
import Logo from '@theme/Logo';
|
||||||
|
@ -88,7 +88,7 @@ function useColorModeToggle() {
|
||||||
const {
|
const {
|
||||||
colorMode: {disableSwitch},
|
colorMode: {disableSwitch},
|
||||||
} = useThemeConfig();
|
} = useThemeConfig();
|
||||||
const {isDarkTheme, setLightTheme, setDarkTheme} = useThemeContext();
|
const {isDarkTheme, setLightTheme, setDarkTheme} = useColorMode();
|
||||||
const toggle = useCallback(
|
const toggle = useCallback(
|
||||||
(e) => (e.target.checked ? setDarkTheme() : setLightTheme()),
|
(e) => (e.target.checked ? setDarkTheme() : setLightTheme()),
|
||||||
[setLightTheme, setDarkTheme],
|
[setLightTheme, setDarkTheme],
|
||||||
|
|
|
@ -9,8 +9,10 @@ import React from 'react';
|
||||||
import renderer from 'react-test-renderer';
|
import renderer from 'react-test-renderer';
|
||||||
import Tabs from '../index';
|
import Tabs from '../index';
|
||||||
import TabItem from '../../TabItem';
|
import TabItem from '../../TabItem';
|
||||||
import UserPreferencesProvider from '@theme/UserPreferencesProvider';
|
import {
|
||||||
import {ScrollControllerProvider} from '@docusaurus/theme-common';
|
TabGroupChoiceProvider,
|
||||||
|
ScrollControllerProvider,
|
||||||
|
} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
describe('Tabs', () => {
|
describe('Tabs', () => {
|
||||||
test('Should reject bad Tabs child', () => {
|
test('Should reject bad Tabs child', () => {
|
||||||
|
@ -57,7 +59,7 @@ describe('Tabs', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
renderer.create(
|
renderer.create(
|
||||||
<ScrollControllerProvider>
|
<ScrollControllerProvider>
|
||||||
<UserPreferencesProvider>
|
<TabGroupChoiceProvider>
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<TabItem value="v1">Tab 1</TabItem>
|
<TabItem value="v1">Tab 1</TabItem>
|
||||||
<TabItem value="v2">Tab 2</TabItem>
|
<TabItem value="v2">Tab 2</TabItem>
|
||||||
|
@ -102,7 +104,7 @@ describe('Tabs', () => {
|
||||||
Tab 2
|
Tab 2
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</UserPreferencesProvider>
|
</TabGroupChoiceProvider>
|
||||||
</ScrollControllerProvider>,
|
</ScrollControllerProvider>,
|
||||||
);
|
);
|
||||||
}).not.toThrow(); // TODO Better Jest infrastructure to mock the Layout
|
}).not.toThrow(); // TODO Better Jest infrastructure to mock the Layout
|
||||||
|
@ -113,7 +115,7 @@ describe('Tabs', () => {
|
||||||
const tabs = ['Apple', 'Banana', 'Carrot'];
|
const tabs = ['Apple', 'Banana', 'Carrot'];
|
||||||
renderer.create(
|
renderer.create(
|
||||||
<ScrollControllerProvider>
|
<ScrollControllerProvider>
|
||||||
<UserPreferencesProvider>
|
<TabGroupChoiceProvider>
|
||||||
<Tabs
|
<Tabs
|
||||||
values={tabs.map((t, idx) => ({label: t, value: idx}))}
|
values={tabs.map((t, idx) => ({label: t, value: idx}))}
|
||||||
defaultValue={0}>
|
defaultValue={0}>
|
||||||
|
@ -121,7 +123,7 @@ describe('Tabs', () => {
|
||||||
<TabItem value={idx}>{t}</TabItem>
|
<TabItem value={idx}>{t}</TabItem>
|
||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</UserPreferencesProvider>
|
</TabGroupChoiceProvider>
|
||||||
</ScrollControllerProvider>,
|
</ScrollControllerProvider>,
|
||||||
);
|
);
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
|
|
|
@ -13,8 +13,11 @@ import React, {
|
||||||
type ReactElement,
|
type ReactElement,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||||
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
|
import {
|
||||||
import {useScrollPositionBlocker, duplicates} from '@docusaurus/theme-common';
|
useScrollPositionBlocker,
|
||||||
|
duplicates,
|
||||||
|
useTabGroupChoice,
|
||||||
|
} from '@docusaurus/theme-common';
|
||||||
import type {Props} from '@theme/Tabs';
|
import type {Props} from '@theme/Tabs';
|
||||||
import type {Props as TabItemProps} from '@theme/TabItem';
|
import type {Props as TabItemProps} from '@theme/TabItem';
|
||||||
|
|
||||||
|
@ -83,7 +86,7 @@ function TabsComponent(props: Props): JSX.Element {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {tabGroupChoices, setTabGroupChoices} = useUserPreferencesContext();
|
const {tabGroupChoices, setTabGroupChoices} = useTabGroupChoice();
|
||||||
const [selectedValue, setSelectedValue] = useState(defaultValue);
|
const [selectedValue, setSelectedValue] = useState(defaultValue);
|
||||||
const tabRefs: (HTMLLIElement | null)[] = [];
|
const tabRefs: (HTMLLIElement | null)[] = [];
|
||||||
const {blockElementScrollPositionUntilNextRender} =
|
const {blockElementScrollPositionUntilNextRender} =
|
||||||
|
|
|
@ -1,15 +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 type {ThemeContextProps} from '@theme/hooks/useThemeContext';
|
|
||||||
|
|
||||||
const ThemeContext = React.createContext<ThemeContextProps | undefined>(
|
|
||||||
undefined,
|
|
||||||
);
|
|
||||||
|
|
||||||
export default ThemeContext;
|
|
|
@ -1,28 +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, {useMemo} from 'react';
|
|
||||||
|
|
||||||
import useTheme from '@theme/hooks/useTheme';
|
|
||||||
import ThemeContext from '@theme/ThemeContext';
|
|
||||||
import type {Props} from '@theme/ThemeProvider';
|
|
||||||
|
|
||||||
function ThemeProvider(props: Props): JSX.Element {
|
|
||||||
const {isDarkTheme, setLightTheme, setDarkTheme} = useTheme();
|
|
||||||
const contextValue = useMemo(
|
|
||||||
() => ({isDarkTheme, setLightTheme, setDarkTheme}),
|
|
||||||
[isDarkTheme, setLightTheme, setDarkTheme],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ThemeContext.Provider value={contextValue}>
|
|
||||||
{props.children}
|
|
||||||
</ThemeContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ThemeProvider;
|
|
|
@ -9,14 +9,14 @@ import React from 'react';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||||
import useThemeContext from '@theme/hooks/useThemeContext';
|
import {useColorMode} from '@docusaurus/theme-common';
|
||||||
import type {Props} from '@theme/ThemedImage';
|
import type {Props} from '@theme/ThemedImage';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
function ThemedImage(props: Props): JSX.Element {
|
function ThemedImage(props: Props): JSX.Element {
|
||||||
const isBrowser = useIsBrowser();
|
const isBrowser = useIsBrowser();
|
||||||
const {isDarkTheme} = useThemeContext();
|
const {isDarkTheme} = useColorMode();
|
||||||
const {sources, className, alt = '', ...propsRest} = props;
|
const {sources, className, alt = '', ...propsRest} = props;
|
||||||
|
|
||||||
type SourceName = keyof Props['sources'];
|
type SourceName = keyof Props['sources'];
|
||||||
|
|
|
@ -1,30 +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, {useMemo} from 'react';
|
|
||||||
|
|
||||||
import useTabGroupChoice from '@theme/hooks/useTabGroupChoice';
|
|
||||||
import UserPreferencesContext from '@theme/UserPreferencesContext';
|
|
||||||
import type {Props} from '@theme/UserPreferencesProvider';
|
|
||||||
|
|
||||||
function UserPreferencesProvider(props: Props): JSX.Element {
|
|
||||||
const {tabGroupChoices, setTabGroupChoices} = useTabGroupChoice();
|
|
||||||
const contextValue = useMemo(
|
|
||||||
() => ({
|
|
||||||
tabGroupChoices,
|
|
||||||
setTabGroupChoices,
|
|
||||||
}),
|
|
||||||
[tabGroupChoices, setTabGroupChoices],
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<UserPreferencesContext.Provider value={contextValue}>
|
|
||||||
{props.children}
|
|
||||||
</UserPreferencesContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default UserPreferencesProvider;
|
|
|
@ -1,46 +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 {useState, useCallback, useEffect} from 'react';
|
|
||||||
import type {useTabGroupChoiceReturns} from '@theme/hooks/useTabGroupChoice';
|
|
||||||
import {createStorageSlot, listStorageKeys} from '@docusaurus/theme-common';
|
|
||||||
|
|
||||||
const TAB_CHOICE_PREFIX = 'docusaurus.tab.';
|
|
||||||
|
|
||||||
const useTabGroupChoice = (): useTabGroupChoiceReturns => {
|
|
||||||
const [tabGroupChoices, setChoices] = useState<{
|
|
||||||
readonly [groupId: string]: string;
|
|
||||||
}>({});
|
|
||||||
const setChoiceSyncWithLocalStorage = useCallback((groupId, newChoice) => {
|
|
||||||
createStorageSlot(`${TAB_CHOICE_PREFIX}${groupId}`).set(newChoice);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
try {
|
|
||||||
const localStorageChoices: Record<string, string> = {};
|
|
||||||
listStorageKeys().forEach((storageKey) => {
|
|
||||||
if (storageKey.startsWith(TAB_CHOICE_PREFIX)) {
|
|
||||||
const groupId = storageKey.substring(TAB_CHOICE_PREFIX.length);
|
|
||||||
localStorageChoices[groupId] = createStorageSlot(storageKey).get()!;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setChoices(localStorageChoices);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
|
||||||
tabGroupChoices,
|
|
||||||
setTabGroupChoices: (groupId: string, newChoice: string) => {
|
|
||||||
setChoices((oldChoices) => ({...oldChoices, [groupId]: newChoice}));
|
|
||||||
setChoiceSyncWithLocalStorage(groupId, newChoice);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useTabGroupChoice;
|
|
|
@ -1,23 +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 {useContext} from 'react';
|
|
||||||
|
|
||||||
import ThemeContext from '@theme/ThemeContext';
|
|
||||||
import type {ThemeContextProps} from '@theme/hooks/useThemeContext';
|
|
||||||
|
|
||||||
function useThemeContext(): ThemeContextProps {
|
|
||||||
const context = useContext<ThemeContextProps | undefined>(ThemeContext);
|
|
||||||
if (context == null) {
|
|
||||||
throw new Error(
|
|
||||||
'"useThemeContext" is used outside of "Layout" component. Please see https://docusaurus.io/docs/api/themes/configuration#usethemecontext.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useThemeContext;
|
|
|
@ -1,25 +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 {useContext} from 'react';
|
|
||||||
|
|
||||||
import UserPreferencesContext from '@theme/UserPreferencesContext';
|
|
||||||
import type {UserPreferencesContextProps} from '@theme/hooks/useUserPreferencesContext';
|
|
||||||
|
|
||||||
function useUserPreferencesContext(): UserPreferencesContextProps {
|
|
||||||
const context = useContext<UserPreferencesContextProps | undefined>(
|
|
||||||
UserPreferencesContext,
|
|
||||||
);
|
|
||||||
if (context == null) {
|
|
||||||
throw new Error(
|
|
||||||
'"useUserPreferencesContext" is used outside of "Layout" component.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useUserPreferencesContext;
|
|
|
@ -6,10 +6,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {useState, useCallback, useRef} from 'react';
|
import {useState, useCallback, useRef} from 'react';
|
||||||
import {useLocationChange, useScrollPosition} from '@docusaurus/theme-common';
|
import {useLocationChange} from '../utils/useLocationChange';
|
||||||
import type {useHideableNavbarReturns} from '@theme/hooks/useHideableNavbar';
|
import {useScrollPosition} from '../utils/scrollUtils';
|
||||||
|
|
||||||
const useHideableNavbar = (hideOnScroll: boolean): useHideableNavbarReturns => {
|
type UseHideableNavbarReturns = {
|
||||||
|
readonly navbarRef: (node: HTMLElement | null) => void;
|
||||||
|
readonly isNavbarVisible: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function useHideableNavbar(
|
||||||
|
hideOnScroll: boolean,
|
||||||
|
): UseHideableNavbarReturns {
|
||||||
const [isNavbarVisible, setIsNavbarVisible] = useState(hideOnScroll);
|
const [isNavbarVisible, setIsNavbarVisible] = useState(hideOnScroll);
|
||||||
const isFocusedAnchor = useRef(false);
|
const isFocusedAnchor = useRef(false);
|
||||||
const navbarHeight = useRef(0);
|
const navbarHeight = useRef(0);
|
||||||
|
@ -67,6 +74,4 @@ const useHideableNavbar = (hideOnScroll: boolean): useHideableNavbarReturns => {
|
||||||
navbarRef,
|
navbarRef,
|
||||||
isNavbarVisible,
|
isNavbarVisible,
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
export default useHideableNavbar;
|
|
|
@ -11,7 +11,7 @@ import './styles.css';
|
||||||
|
|
||||||
// This hook detect keyboard focus indicator to not show outline for mouse users
|
// This hook detect keyboard focus indicator to not show outline for mouse users
|
||||||
// Inspired by https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2
|
// Inspired by https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2
|
||||||
function useKeyboardNavigation(): void {
|
export default function useKeyboardNavigation(): void {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const keyboardFocusedClassName = 'navigation-with-keyboard';
|
const keyboardFocusedClassName = 'navigation-with-keyboard';
|
||||||
|
|
||||||
|
@ -35,5 +35,3 @@ function useKeyboardNavigation(): void {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useKeyboardNavigation;
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import {useEffect} from 'react';
|
import {useEffect} from 'react';
|
||||||
|
|
||||||
function useLockBodyScroll(lock: boolean = true): void {
|
export default function useLockBodyScroll(lock: boolean = true): void {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.body.style.overflow = lock ? 'hidden' : 'visible';
|
document.body.style.overflow = lock ? 'hidden' : 'visible';
|
||||||
|
|
||||||
|
@ -16,5 +16,3 @@ function useLockBodyScroll(lock: boolean = true): void {
|
||||||
};
|
};
|
||||||
}, [lock]);
|
}, [lock]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useLockBodyScroll;
|
|
|
@ -6,17 +6,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import defaultTheme from 'prism-react-renderer/themes/palenight';
|
import defaultTheme from 'prism-react-renderer/themes/palenight';
|
||||||
import useThemeContext from '@theme/hooks/useThemeContext';
|
import {useColorMode} from '../utils/colorModeUtils';
|
||||||
import {useThemeConfig} from '@docusaurus/theme-common';
|
import {useThemeConfig} from '../utils/useThemeConfig';
|
||||||
|
|
||||||
const usePrismTheme = (): typeof defaultTheme => {
|
export default function usePrismTheme(): typeof defaultTheme {
|
||||||
const {prism} = useThemeConfig();
|
const {prism} = useThemeConfig();
|
||||||
const {isDarkTheme} = useThemeContext();
|
const {isDarkTheme} = useColorMode();
|
||||||
const lightModeTheme = prism.theme || defaultTheme;
|
const lightModeTheme = prism.theme || defaultTheme;
|
||||||
const darkModeTheme = prism.darkTheme || lightModeTheme;
|
const darkModeTheme = prism.darkTheme || lightModeTheme;
|
||||||
const prismTheme = isDarkTheme ? darkModeTheme : lightModeTheme;
|
const prismTheme = isDarkTheme ? darkModeTheme : lightModeTheme;
|
||||||
|
|
||||||
return prismTheme;
|
return prismTheme;
|
||||||
};
|
}
|
||||||
|
|
||||||
export default usePrismTheme;
|
|
|
@ -8,11 +8,16 @@
|
||||||
import {useHistory} from '@docusaurus/router';
|
import {useHistory} from '@docusaurus/router';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import {useCallback, useEffect, useState} from 'react';
|
import {useCallback, useEffect, useState} from 'react';
|
||||||
import type {SearchQuery} from '@theme/hooks/useSearchQuery';
|
|
||||||
|
|
||||||
const SEARCH_PARAM_QUERY = 'q';
|
const SEARCH_PARAM_QUERY = 'q';
|
||||||
|
|
||||||
function useSearchQuery(): SearchQuery {
|
interface UseSearchPageReturn {
|
||||||
|
searchQuery: string;
|
||||||
|
setSearchQuery: (newSearchQuery: string) => void;
|
||||||
|
generateSearchPageLink: (targetSearchQuery: string) => string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useSearchPage(): UseSearchPageReturn {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const {
|
const {
|
||||||
siteConfig: {baseUrl},
|
siteConfig: {baseUrl},
|
||||||
|
@ -59,5 +64,3 @@ function useSearchQuery(): SearchQuery {
|
||||||
generateSearchPageLink,
|
generateSearchPageLink,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useSearchQuery;
|
|
|
@ -8,7 +8,6 @@
|
||||||
import {useEffect, useState} from 'react';
|
import {useEffect, useState} from 'react';
|
||||||
|
|
||||||
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
||||||
import type {WindowSize} from '@theme/hooks/useWindowSize';
|
|
||||||
|
|
||||||
const windowSizes = {
|
const windowSizes = {
|
||||||
desktop: 'desktop',
|
desktop: 'desktop',
|
||||||
|
@ -21,6 +20,8 @@ const windowSizes = {
|
||||||
ssr: 'ssr',
|
ssr: 'ssr',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
type WindowSize = keyof typeof windowSizes;
|
||||||
|
|
||||||
const DesktopThresholdWidth = 996;
|
const DesktopThresholdWidth = 996;
|
||||||
|
|
||||||
function getWindowSize() {
|
function getWindowSize() {
|
||||||
|
@ -38,7 +39,7 @@ const DevSimulateSSR = process.env.NODE_ENV === 'development' && true;
|
||||||
// This hook returns an enum value on purpose!
|
// This hook returns an enum value on purpose!
|
||||||
// We don't want it to return the actual width value, for resize perf reasons
|
// We don't want it to return the actual width value, for resize perf reasons
|
||||||
// We only want to re-render once a breakpoint is crossed
|
// We only want to re-render once a breakpoint is crossed
|
||||||
function useWindowSize(): WindowSize {
|
export default function useWindowSize(): WindowSize {
|
||||||
const [windowSize, setWindowSize] = useState<WindowSize>(() => {
|
const [windowSize, setWindowSize] = useState<WindowSize>(() => {
|
||||||
if (DevSimulateSSR) {
|
if (DevSimulateSSR) {
|
||||||
return 'ssr';
|
return 'ssr';
|
||||||
|
@ -65,5 +66,3 @@ function useWindowSize(): WindowSize {
|
||||||
|
|
||||||
return windowSize;
|
return windowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useWindowSize;
|
|
|
@ -114,3 +114,16 @@ export {
|
||||||
} from './utils/reactUtils';
|
} from './utils/reactUtils';
|
||||||
|
|
||||||
export {isRegexpStringMatch} from './utils/regexpUtils';
|
export {isRegexpStringMatch} from './utils/regexpUtils';
|
||||||
|
|
||||||
|
export {useColorMode, ColorModeProvider} from './utils/colorModeUtils';
|
||||||
|
export {
|
||||||
|
useTabGroupChoice,
|
||||||
|
TabGroupChoiceProvider,
|
||||||
|
} from './utils/tabGroupChoiceUtils';
|
||||||
|
|
||||||
|
export {default as useHideableNavbar} from './hooks/useHideableNavbar';
|
||||||
|
export {default as useKeyboardNavigation} from './hooks/useKeyboardNavigation';
|
||||||
|
export {default as usePrismTheme} from './hooks/usePrismTheme';
|
||||||
|
export {default as useLockBodyScroll} from './hooks/useLockBodyScroll';
|
||||||
|
export {default as useWindowSize} from './hooks/useWindowSize';
|
||||||
|
export {default as useSearchPage} from './hooks/useSearchPage';
|
||||||
|
|
|
@ -5,11 +5,24 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {useState, useCallback, useEffect} from 'react';
|
import type {ReactNode} from 'react';
|
||||||
|
import React, {
|
||||||
|
useState,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useContext,
|
||||||
|
useMemo,
|
||||||
|
} from 'react';
|
||||||
|
|
||||||
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
||||||
import type {useThemeReturns} from '@theme/hooks/useTheme';
|
import {createStorageSlot} from './storageUtils';
|
||||||
import {useThemeConfig, createStorageSlot} from '@docusaurus/theme-common';
|
import {useThemeConfig} from './useThemeConfig';
|
||||||
|
|
||||||
|
type ColorModeContextValue = {
|
||||||
|
readonly isDarkTheme: boolean;
|
||||||
|
readonly setLightTheme: () => void;
|
||||||
|
readonly setDarkTheme: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
const ThemeStorage = createStorageSlot('theme');
|
const ThemeStorage = createStorageSlot('theme');
|
||||||
|
|
||||||
|
@ -35,7 +48,7 @@ const storeTheme = (newTheme: Themes) => {
|
||||||
createStorageSlot('theme').set(coerceToTheme(newTheme));
|
createStorageSlot('theme').set(coerceToTheme(newTheme));
|
||||||
};
|
};
|
||||||
|
|
||||||
const useTheme = (): useThemeReturns => {
|
function useColorModeContextValue(): ColorModeContextValue {
|
||||||
const {
|
const {
|
||||||
colorMode: {defaultMode, disableSwitch, respectPrefersColorScheme},
|
colorMode: {defaultMode, disableSwitch, respectPrefersColorScheme},
|
||||||
} = useThemeConfig();
|
} = useThemeConfig();
|
||||||
|
@ -86,6 +99,37 @@ const useTheme = (): useThemeReturns => {
|
||||||
setLightTheme,
|
setLightTheme,
|
||||||
setDarkTheme,
|
setDarkTheme,
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
export default useTheme;
|
const ColorModeContext = React.createContext<ColorModeContextValue | undefined>(
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
export function ColorModeProvider({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
}): JSX.Element {
|
||||||
|
const {isDarkTheme, setLightTheme, setDarkTheme} = useColorModeContextValue();
|
||||||
|
const contextValue = useMemo(
|
||||||
|
() => ({isDarkTheme, setLightTheme, setDarkTheme}),
|
||||||
|
[isDarkTheme, setLightTheme, setDarkTheme],
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<ColorModeContext.Provider value={contextValue}>
|
||||||
|
{children}
|
||||||
|
</ColorModeContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useColorMode(): ColorModeContextValue {
|
||||||
|
const context = useContext<ColorModeContextValue | undefined>(
|
||||||
|
ColorModeContext,
|
||||||
|
);
|
||||||
|
if (context == null) {
|
||||||
|
throw new Error(
|
||||||
|
'"useColorMode()" is used outside of "Layout" component. Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/**
|
||||||
|
* 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, {
|
||||||
|
useState,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
createContext,
|
||||||
|
useMemo,
|
||||||
|
useContext,
|
||||||
|
type ReactNode,
|
||||||
|
} from 'react';
|
||||||
|
import {createStorageSlot, listStorageKeys} from './storageUtils';
|
||||||
|
|
||||||
|
const TAB_CHOICE_PREFIX = 'docusaurus.tab.';
|
||||||
|
|
||||||
|
type TabGroupChoiceContextValue = {
|
||||||
|
readonly tabGroupChoices: {readonly [groupId: string]: string};
|
||||||
|
readonly setTabGroupChoices: (groupId: string, newChoice: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TabGroupChoiceContext = createContext<
|
||||||
|
TabGroupChoiceContextValue | undefined
|
||||||
|
>(undefined);
|
||||||
|
|
||||||
|
function useTabGroupChoiceContextValue(): TabGroupChoiceContextValue {
|
||||||
|
const [tabGroupChoices, setChoices] = useState<{
|
||||||
|
readonly [groupId: string]: string;
|
||||||
|
}>({});
|
||||||
|
const setChoiceSyncWithLocalStorage = useCallback((groupId, newChoice) => {
|
||||||
|
createStorageSlot(`${TAB_CHOICE_PREFIX}${groupId}`).set(newChoice);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
try {
|
||||||
|
const localStorageChoices: Record<string, string> = {};
|
||||||
|
listStorageKeys().forEach((storageKey) => {
|
||||||
|
if (storageKey.startsWith(TAB_CHOICE_PREFIX)) {
|
||||||
|
const groupId = storageKey.substring(TAB_CHOICE_PREFIX.length);
|
||||||
|
localStorageChoices[groupId] = createStorageSlot(storageKey).get()!;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setChoices(localStorageChoices);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
tabGroupChoices,
|
||||||
|
setTabGroupChoices: (groupId: string, newChoice: string) => {
|
||||||
|
setChoices((oldChoices) => ({...oldChoices, [groupId]: newChoice}));
|
||||||
|
setChoiceSyncWithLocalStorage(groupId, newChoice);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TabGroupChoiceProvider({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
}): JSX.Element {
|
||||||
|
const {tabGroupChoices, setTabGroupChoices} = useTabGroupChoiceContextValue();
|
||||||
|
const contextValue = useMemo(
|
||||||
|
() => ({
|
||||||
|
tabGroupChoices,
|
||||||
|
setTabGroupChoices,
|
||||||
|
}),
|
||||||
|
[tabGroupChoices, setTabGroupChoices],
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<TabGroupChoiceContext.Provider value={contextValue}>
|
||||||
|
{children}
|
||||||
|
</TabGroupChoiceContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTabGroupChoice(): TabGroupChoiceContextValue {
|
||||||
|
const context = useContext(TabGroupChoiceContext);
|
||||||
|
if (context == null) {
|
||||||
|
throw new Error(
|
||||||
|
'"useUserPreferencesContext" is used outside of "Layout" component.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
|
@ -18,6 +18,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-beta.14",
|
"@docusaurus/core": "2.0.0-beta.14",
|
||||||
|
"@docusaurus/theme-common": "2.0.0-beta.14",
|
||||||
"@docusaurus/theme-translations": "2.0.0-beta.14",
|
"@docusaurus/theme-translations": "2.0.0-beta.14",
|
||||||
"@docusaurus/utils": "2.0.0-beta.14",
|
"@docusaurus/utils": "2.0.0-beta.14",
|
||||||
"@docusaurus/utils-validation": "2.0.0-beta.14",
|
"@docusaurus/utils-validation": "2.0.0-beta.14",
|
||||||
|
|
|
@ -11,7 +11,7 @@ import clsx from 'clsx';
|
||||||
import Translate from '@docusaurus/Translate';
|
import Translate from '@docusaurus/Translate';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import BrowserOnly from '@docusaurus/BrowserOnly';
|
import BrowserOnly from '@docusaurus/BrowserOnly';
|
||||||
import usePrismTheme from '@theme/hooks/usePrismTheme';
|
import {usePrismTheme} from '@docusaurus/theme-common';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
"version": "2.0.0-beta.14",
|
"version": "2.0.0-beta.14",
|
||||||
"description": "Algolia search component for Docusaurus.",
|
"description": "Algolia search component for Docusaurus.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
|
"exports": {
|
||||||
|
"./client": "./lib/client/index.js",
|
||||||
|
".": "./lib/index.js"
|
||||||
|
},
|
||||||
"types": "src/theme-search-algolia.d.ts",
|
"types": "src/theme-search-algolia.d.ts",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|
|
@ -5,8 +5,4 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {createContext} from 'react';
|
export {useAlgoliaContextualFacetFilters} from './useAlgoliaContextualFacetFilters';
|
||||||
|
|
||||||
const UserPreferencesContext = createContext(undefined);
|
|
||||||
|
|
||||||
export default UserPreferencesContext;
|
|
|
@ -5,11 +5,10 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {useAlgoliaContextualFacetFiltersReturns} from '@theme/hooks/useAlgoliaContextualFacetFilters';
|
|
||||||
import {useContextualSearchFilters} from '@docusaurus/theme-common';
|
import {useContextualSearchFilters} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
// Translate search-engine agnostic search filters to Algolia search filters
|
// Translate search-engine agnostic search filters to Algolia search filters
|
||||||
export default function useAlgoliaContextualFacetFilters(): useAlgoliaContextualFacetFiltersReturns {
|
export function useAlgoliaContextualFacetFilters() {
|
||||||
const {locale, tags} = useContextualSearchFilters();
|
const {locale, tags} = useContextualSearchFilters();
|
||||||
|
|
||||||
// seems safe to convert locale->language, see AlgoliaSearchMetadata comment
|
// seems safe to convert locale->language, see AlgoliaSearchMetadata comment
|
|
@ -5,24 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
declare module '@docusaurus/theme-search-algolia' {
|
declare module '@docusaurus/theme-search-algolia/client' {
|
||||||
export type Options = never;
|
export function useAlgoliaContextualFacetFilters(): [string, string[]];
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/hooks/useSearchQuery' {
|
|
||||||
export interface SearchQuery {
|
|
||||||
searchQuery: string;
|
|
||||||
setSearchQuery: (newSearchQuery: string) => void;
|
|
||||||
generateSearchPageLink: (targetSearchQuery: string) => string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function useSearchQuery(): SearchQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/hooks/useAlgoliaContextualFacetFilters' {
|
|
||||||
export type useAlgoliaContextualFacetFiltersReturns = [string, string[]];
|
|
||||||
|
|
||||||
export default function useAlgoliaContextualFacetFilters(): useAlgoliaContextualFacetFiltersReturns;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/SearchPage' {
|
declare module '@theme/SearchPage' {
|
||||||
|
|
|
@ -13,10 +13,9 @@ import {useHistory} from '@docusaurus/router';
|
||||||
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
|
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
import Head from '@docusaurus/Head';
|
import Head from '@docusaurus/Head';
|
||||||
import useSearchQuery from '@theme/hooks/useSearchQuery';
|
import {isRegexpStringMatch, useSearchPage} from '@docusaurus/theme-common';
|
||||||
import {isRegexpStringMatch} from '@docusaurus/theme-common';
|
|
||||||
import {DocSearchButton, useDocSearchKeyboardEvents} from '@docsearch/react';
|
import {DocSearchButton, useDocSearchKeyboardEvents} from '@docsearch/react';
|
||||||
import useAlgoliaContextualFacetFilters from '@theme/hooks/useAlgoliaContextualFacetFilters';
|
import {useAlgoliaContextualFacetFilters} from '@docusaurus/theme-search-algolia/client';
|
||||||
import {translate} from '@docusaurus/Translate';
|
import {translate} from '@docusaurus/Translate';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
@ -56,7 +55,7 @@ type ResultsFooterProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function ResultsFooter({state, onClose}: ResultsFooterProps) {
|
function ResultsFooter({state, onClose}: ResultsFooterProps) {
|
||||||
const {generateSearchPageLink} = useSearchQuery();
|
const {generateSearchPageLink} = useSearchPage();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link to={generateSearchPageLink(state.query)} onClick={onClose}>
|
<Link to={generateSearchPageLink(state.query)} onClick={onClose}>
|
||||||
|
|
|
@ -22,10 +22,10 @@ import {
|
||||||
usePluralForm,
|
usePluralForm,
|
||||||
isRegexpStringMatch,
|
isRegexpStringMatch,
|
||||||
useDynamicCallback,
|
useDynamicCallback,
|
||||||
|
useSearchPage,
|
||||||
} from '@docusaurus/theme-common';
|
} from '@docusaurus/theme-common';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import {useAllDocsData} from '@docusaurus/plugin-content-docs/client';
|
import {useAllDocsData} from '@docusaurus/plugin-content-docs/client';
|
||||||
import useSearchQuery from '@theme/hooks/useSearchQuery';
|
|
||||||
import Layout from '@theme/Layout';
|
import Layout from '@theme/Layout';
|
||||||
import Translate, {translate} from '@docusaurus/Translate';
|
import Translate, {translate} from '@docusaurus/Translate';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
@ -162,7 +162,7 @@ function SearchPage(): JSX.Element {
|
||||||
const documentsFoundPlural = useDocumentsFoundPlural();
|
const documentsFoundPlural = useDocumentsFoundPlural();
|
||||||
|
|
||||||
const docsSearchVersionsHelpers = useDocsSearchVersionsHelpers();
|
const docsSearchVersionsHelpers = useDocsSearchVersionsHelpers();
|
||||||
const {searchQuery, setSearchQuery} = useSearchQuery();
|
const {searchQuery, setSearchQuery} = useSearchPage();
|
||||||
const initialSearchResultState: ResultDispatcherState = {
|
const initialSearchResultState: ResultDispatcherState = {
|
||||||
items: [],
|
items: [],
|
||||||
query: null,
|
query: null,
|
||||||
|
|
|
@ -4,5 +4,5 @@
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"jsx": "react-native"
|
"jsx": "react-native"
|
||||||
},
|
},
|
||||||
"include": ["src/theme/", "src/*.d.ts"]
|
"include": ["src/theme/", "src/client/", "src/*.d.ts"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -905,20 +905,20 @@ module.exports = {
|
||||||
|
|
||||||
## Hooks {#hooks}
|
## Hooks {#hooks}
|
||||||
|
|
||||||
### `useThemeContext` {#usethemecontext}
|
### `useColorMode` {#use-color-mode}
|
||||||
|
|
||||||
React hook to access theme context. This context contains functions for setting light and dark mode and exposes boolean variable, indicating which mode is currently in use.
|
A React hook to access the color context. This context contains functions for setting light and dark mode and exposes boolean variable, indicating which mode is currently in use.
|
||||||
|
|
||||||
Usage example:
|
Usage example:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
// highlight-next-line
|
// highlight-next-line
|
||||||
import useThemeContext from '@theme/hooks/useThemeContext';
|
import {useColorMode} from '@docusaurus/theme-common';
|
||||||
|
|
||||||
const Example = () => {
|
const Example = () => {
|
||||||
// highlight-next-line
|
// highlight-next-line
|
||||||
const {isDarkTheme, setLightTheme, setDarkTheme} = useThemeContext();
|
const {isDarkTheme, setLightTheme, setDarkTheme} = useColorMode();
|
||||||
|
|
||||||
return <h1>Dark mode is now {isDarkTheme ? 'on' : 'off'}</h1>;
|
return <h1>Dark mode is now {isDarkTheme ? 'on' : 'off'}</h1>;
|
||||||
};
|
};
|
||||||
|
@ -926,7 +926,7 @@ const Example = () => {
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
||||||
The component calling `useThemeContext` must be a child of the `Layout` component.
|
The component calling `useColorMode` must be a child of the `Layout` component.
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
function ExamplePage() {
|
function ExamplePage() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue