@azerion/bunosaurus-theme-common 0.0.0-stage → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/lib/components/Collapsible/index.d.ts +59 -0
- package/lib/components/Collapsible/index.d.ts.map +1 -0
- package/lib/components/Collapsible/index.js +145 -0
- package/lib/components/Collapsible/index.js.map +1 -0
- package/lib/components/Details/index.d.ts +20 -0
- package/lib/components/Details/index.d.ts.map +1 -0
- package/lib/components/Details/index.js +86 -0
- package/lib/components/Details/index.js.map +1 -0
- package/lib/components/Details/styles.module.css +66 -0
- package/lib/components/ThemedComponent/index.d.ts +31 -0
- package/lib/components/ThemedComponent/index.d.ts.map +1 -0
- package/lib/components/ThemedComponent/index.js +47 -0
- package/lib/components/ThemedComponent/index.js.map +1 -0
- package/lib/components/ThemedComponent/styles.module.css +26 -0
- package/lib/contexts/announcementBar.d.ts +21 -0
- package/lib/contexts/announcementBar.d.ts.map +1 -0
- package/lib/contexts/announcementBar.js +72 -0
- package/lib/contexts/announcementBar.js.map +1 -0
- package/lib/contexts/colorMode.d.ts +23 -0
- package/lib/contexts/colorMode.d.ts.map +1 -0
- package/lib/contexts/colorMode.js +163 -0
- package/lib/contexts/colorMode.js.map +1 -0
- package/lib/contexts/navbarMobileSidebar.d.ts +31 -0
- package/lib/contexts/navbarMobileSidebar.d.ts.map +1 -0
- package/lib/contexts/navbarMobileSidebar.js +65 -0
- package/lib/contexts/navbarMobileSidebar.js.map +1 -0
- package/lib/contexts/navbarSecondaryMenu/content.d.ts +37 -0
- package/lib/contexts/navbarSecondaryMenu/content.d.ts.map +1 -0
- package/lib/contexts/navbarSecondaryMenu/content.js +50 -0
- package/lib/contexts/navbarSecondaryMenu/content.js.map +1 -0
- package/lib/contexts/navbarSecondaryMenu/display.d.ts +24 -0
- package/lib/contexts/navbarSecondaryMenu/display.d.ts.map +1 -0
- package/lib/contexts/navbarSecondaryMenu/display.js +62 -0
- package/lib/contexts/navbarSecondaryMenu/display.js.map +1 -0
- package/lib/hooks/useBackToTopButton.d.ts +27 -0
- package/lib/hooks/useBackToTopButton.d.ts.map +1 -0
- package/lib/hooks/useBackToTopButton.js +50 -0
- package/lib/hooks/useBackToTopButton.js.map +1 -0
- package/lib/hooks/useCodeWordWrap.d.ts +15 -0
- package/lib/hooks/useCodeWordWrap.d.ts.map +1 -0
- package/lib/hooks/useCodeWordWrap.js +67 -0
- package/lib/hooks/useCodeWordWrap.js.map +1 -0
- package/lib/hooks/useHideableNavbar.d.ts +17 -0
- package/lib/hooks/useHideableNavbar.d.ts.map +1 -0
- package/lib/hooks/useHideableNavbar.js +65 -0
- package/lib/hooks/useHideableNavbar.js.map +1 -0
- package/lib/hooks/useLockBodyScroll.d.ts +12 -0
- package/lib/hooks/useLockBodyScroll.d.ts.map +1 -0
- package/lib/hooks/useLockBodyScroll.js +20 -0
- package/lib/hooks/useLockBodyScroll.js.map +1 -0
- package/lib/hooks/useMutationObserver.d.ts +4 -0
- package/lib/hooks/useMutationObserver.d.ts.map +1 -0
- package/lib/hooks/useMutationObserver.js +29 -0
- package/lib/hooks/useMutationObserver.js.map +1 -0
- package/lib/hooks/usePrismTheme.d.ts +13 -0
- package/lib/hooks/usePrismTheme.d.ts.map +1 -0
- package/lib/hooks/usePrismTheme.js +21 -0
- package/lib/hooks/usePrismTheme.js.map +1 -0
- package/lib/hooks/useTOCHighlight.d.ts +25 -0
- package/lib/hooks/useTOCHighlight.d.ts.map +1 -0
- package/lib/hooks/useTOCHighlight.js +130 -0
- package/lib/hooks/useTOCHighlight.js.map +1 -0
- package/lib/hooks/useWindowSize.d.ts +27 -0
- package/lib/hooks/useWindowSize.d.ts.map +1 -0
- package/lib/hooks/useWindowSize.js +49 -0
- package/lib/hooks/useWindowSize.js.map +1 -0
- package/lib/index.d.ts +30 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +37 -0
- package/lib/index.js.map +1 -0
- package/lib/internal.d.ts +35 -0
- package/lib/internal.d.ts.map +1 -0
- package/lib/internal.js +45 -0
- package/lib/internal.js.map +1 -0
- package/lib/translations/blogTranslations.d.ts +20 -0
- package/lib/translations/blogTranslations.d.ts.map +1 -0
- package/lib/translations/blogTranslations.js +52 -0
- package/lib/translations/blogTranslations.js.map +1 -0
- package/lib/translations/contentVisibilityTranslations.d.ts +12 -0
- package/lib/translations/contentVisibilityTranslations.d.ts.map +1 -0
- package/lib/translations/contentVisibilityTranslations.js +30 -0
- package/lib/translations/contentVisibilityTranslations.js.map +1 -0
- package/lib/translations/docsTranslations.d.ts +8 -0
- package/lib/translations/docsTranslations.d.ts.map +1 -0
- package/lib/translations/docsTranslations.js +17 -0
- package/lib/translations/docsTranslations.js.map +1 -0
- package/lib/utils/IntlUtils.d.ts +2 -0
- package/lib/utils/IntlUtils.d.ts.map +1 -0
- package/lib/utils/IntlUtils.js +20 -0
- package/lib/utils/IntlUtils.js.map +1 -0
- package/lib/utils/ThemeClassNames.d.ts +99 -0
- package/lib/utils/ThemeClassNames.d.ts.map +1 -0
- package/lib/utils/ThemeClassNames.js +107 -0
- package/lib/utils/ThemeClassNames.js.map +1 -0
- package/lib/utils/accessibilityUtils.d.ts +8 -0
- package/lib/utils/accessibilityUtils.d.ts.map +1 -0
- package/lib/utils/accessibilityUtils.js +10 -0
- package/lib/utils/accessibilityUtils.js.map +1 -0
- package/lib/utils/admonitionUtils.d.ts +12 -0
- package/lib/utils/admonitionUtils.d.ts.map +1 -0
- package/lib/utils/admonitionUtils.js +32 -0
- package/lib/utils/admonitionUtils.js.map +1 -0
- package/lib/utils/anchorUtils.d.ts +16 -0
- package/lib/utils/anchorUtils.d.ts.map +1 -0
- package/lib/utils/anchorUtils.js +26 -0
- package/lib/utils/anchorUtils.js.map +1 -0
- package/lib/utils/anchorUtils.module.css +14 -0
- package/lib/utils/codeBlockUtils.d.ts +101 -0
- package/lib/utils/codeBlockUtils.d.ts.map +1 -0
- package/lib/utils/codeBlockUtils.js +310 -0
- package/lib/utils/codeBlockUtils.js.map +1 -0
- package/lib/utils/emojiUtils.d.ts +20 -0
- package/lib/utils/emojiUtils.d.ts.map +1 -0
- package/lib/utils/emojiUtils.js +32 -0
- package/lib/utils/emojiUtils.js.map +1 -0
- package/lib/utils/errorBoundaryUtils.d.ts +31 -0
- package/lib/utils/errorBoundaryUtils.d.ts.map +1 -0
- package/lib/utils/errorBoundaryUtils.js +48 -0
- package/lib/utils/errorBoundaryUtils.js.map +1 -0
- package/lib/utils/errorBoundaryUtils.module.css +16 -0
- package/lib/utils/footerUtils.d.ts +13 -0
- package/lib/utils/footerUtils.d.ts.map +1 -0
- package/lib/utils/footerUtils.js +14 -0
- package/lib/utils/footerUtils.js.map +1 -0
- package/lib/utils/historyUtils.d.ts +39 -0
- package/lib/utils/historyUtils.d.ts.map +1 -0
- package/lib/utils/historyUtils.js +148 -0
- package/lib/utils/historyUtils.js.map +1 -0
- package/lib/utils/jsUtils.d.ts +24 -0
- package/lib/utils/jsUtils.d.ts.map +1 -0
- package/lib/utils/jsUtils.js +43 -0
- package/lib/utils/jsUtils.js.map +1 -0
- package/lib/utils/metadataUtils.d.ts +38 -0
- package/lib/utils/metadataUtils.d.ts.map +1 -0
- package/lib/utils/metadataUtils.js +87 -0
- package/lib/utils/metadataUtils.js.map +1 -0
- package/lib/utils/navbarUtils.d.ts +21 -0
- package/lib/utils/navbarUtils.d.ts.map +1 -0
- package/lib/utils/navbarUtils.js +35 -0
- package/lib/utils/navbarUtils.js.map +1 -0
- package/lib/utils/reactUtils.d.ts +60 -0
- package/lib/utils/reactUtils.d.ts.map +1 -0
- package/lib/utils/reactUtils.js +91 -0
- package/lib/utils/reactUtils.js.map +1 -0
- package/lib/utils/regexpUtils.d.ts +12 -0
- package/lib/utils/regexpUtils.d.ts.map +1 -0
- package/lib/utils/regexpUtils.js +18 -0
- package/lib/utils/regexpUtils.js.map +1 -0
- package/lib/utils/routesUtils.d.ts +26 -0
- package/lib/utils/routesUtils.d.ts.map +1 -0
- package/lib/utils/routesUtils.js +54 -0
- package/lib/utils/routesUtils.js.map +1 -0
- package/lib/utils/scrollUtils.d.ts +83 -0
- package/lib/utils/scrollUtils.d.ts.map +1 -0
- package/lib/utils/scrollUtils.js +201 -0
- package/lib/utils/scrollUtils.js.map +1 -0
- package/lib/utils/searchUtils.d.ts +8 -0
- package/lib/utils/searchUtils.d.ts.map +1 -0
- package/lib/utils/searchUtils.js +8 -0
- package/lib/utils/searchUtils.js.map +1 -0
- package/lib/utils/skipToContentUtils.d.ts +20 -0
- package/lib/utils/skipToContentUtils.d.ts.map +1 -0
- package/lib/utils/skipToContentUtils.js +75 -0
- package/lib/utils/skipToContentUtils.js.map +1 -0
- package/lib/utils/storageUtils.d.ts +36 -0
- package/lib/utils/storageUtils.d.ts.map +1 -0
- package/lib/utils/storageUtils.js +193 -0
- package/lib/utils/storageUtils.js.map +1 -0
- package/lib/utils/tabsUtils.d.ts +55 -0
- package/lib/utils/tabsUtils.d.ts.map +1 -0
- package/lib/utils/tabsUtils.js +179 -0
- package/lib/utils/tabsUtils.js.map +1 -0
- package/lib/utils/tagsUtils.d.ts +20 -0
- package/lib/utils/tagsUtils.d.ts.map +1 -0
- package/lib/utils/tagsUtils.js +41 -0
- package/lib/utils/tagsUtils.js.map +1 -0
- package/lib/utils/titleFormatterUtils.d.ts +59 -0
- package/lib/utils/titleFormatterUtils.d.ts.map +1 -0
- package/lib/utils/titleFormatterUtils.js +49 -0
- package/lib/utils/titleFormatterUtils.js.map +1 -0
- package/lib/utils/tocUtils.d.ts +36 -0
- package/lib/utils/tocUtils.d.ts.map +1 -0
- package/lib/utils/tocUtils.js +84 -0
- package/lib/utils/tocUtils.js.map +1 -0
- package/lib/utils/useAlternatePageUtils.d.ts +32 -0
- package/lib/utils/useAlternatePageUtils.d.ts.map +1 -0
- package/lib/utils/useAlternatePageUtils.js +42 -0
- package/lib/utils/useAlternatePageUtils.js.map +1 -0
- package/lib/utils/useLocalPathname.d.ts +13 -0
- package/lib/utils/useLocalPathname.d.ts.map +1 -0
- package/lib/utils/useLocalPathname.js +19 -0
- package/lib/utils/useLocalPathname.js.map +1 -0
- package/lib/utils/useLocationChange.d.ts +17 -0
- package/lib/utils/useLocationChange.d.ts.map +1 -0
- package/lib/utils/useLocationChange.js +31 -0
- package/lib/utils/useLocationChange.js.map +1 -0
- package/lib/utils/usePluralForm.d.ts +21 -0
- package/lib/utils/usePluralForm.d.ts.map +1 -0
- package/lib/utils/usePluralForm.js +93 -0
- package/lib/utils/usePluralForm.js.map +1 -0
- package/lib/utils/useThemeConfig.d.ts +120 -0
- package/lib/utils/useThemeConfig.d.ts.map +1 -0
- package/lib/utils/useThemeConfig.js +14 -0
- package/lib/utils/useThemeConfig.js.map +1 -0
- package/package.json +58 -4
- package/src/components/Collapsible/index.tsx +250 -0
- package/src/components/Details/index.tsx +130 -0
- package/src/components/Details/styles.module.css +66 -0
- package/src/components/ThemedComponent/index.tsx +75 -0
- package/src/components/ThemedComponent/styles.module.css +26 -0
- package/src/contexts/announcementBar.tsx +117 -0
- package/src/contexts/colorMode.tsx +257 -0
- package/src/contexts/navbarMobileSidebar.tsx +119 -0
- package/src/contexts/navbarSecondaryMenu/content.tsx +100 -0
- package/src/contexts/navbarSecondaryMenu/display.tsx +102 -0
- package/src/hooks/useBackToTopButton.ts +73 -0
- package/src/hooks/useCodeWordWrap.ts +107 -0
- package/src/hooks/useHideableNavbar.ts +81 -0
- package/src/hooks/useLockBodyScroll.ts +21 -0
- package/src/hooks/useMutationObserver.ts +38 -0
- package/src/hooks/usePrismTheme.ts +24 -0
- package/src/hooks/useTOCHighlight.ts +189 -0
- package/src/hooks/useWindowSize.ts +67 -0
- package/src/index.ts +112 -0
- package/src/internal.ts +107 -0
- package/src/translations/blogTranslations.tsx +89 -0
- package/src/translations/contentVisibilityTranslations.tsx +51 -0
- package/src/translations/docsTranslations.tsx +28 -0
- package/src/types.d.ts +8 -0
- package/src/utils/IntlUtils.ts +27 -0
- package/src/utils/ThemeClassNames.ts +119 -0
- package/src/utils/accessibilityUtils.ts +10 -0
- package/src/utils/admonitionUtils.tsx +44 -0
- package/src/utils/anchorUtils.module.css +14 -0
- package/src/utils/anchorUtils.ts +31 -0
- package/src/utils/codeBlockUtils.tsx +494 -0
- package/src/utils/emojiUtils.ts +40 -0
- package/src/utils/errorBoundaryUtils.module.css +16 -0
- package/src/utils/errorBoundaryUtils.tsx +71 -0
- package/src/utils/footerUtils.ts +18 -0
- package/src/utils/historyUtils.ts +199 -0
- package/src/utils/jsUtils.ts +54 -0
- package/src/utils/metadataUtils.tsx +145 -0
- package/src/utils/navbarUtils.tsx +45 -0
- package/src/utils/reactUtils.tsx +120 -0
- package/src/utils/regexpUtils.ts +24 -0
- package/src/utils/routesUtils.ts +75 -0
- package/src/utils/scrollUtils.tsx +303 -0
- package/src/utils/searchUtils.ts +8 -0
- package/src/utils/skipToContentUtils.tsx +108 -0
- package/src/utils/storageUtils.ts +260 -0
- package/src/utils/tabsUtils.tsx +307 -0
- package/src/utils/tagsUtils.tsx +61 -0
- package/src/utils/titleFormatterUtils.tsx +120 -0
- package/src/utils/tocUtils.ts +119 -0
- package/src/utils/useAlternatePageUtils.ts +80 -0
- package/src/utils/useLocalPathname.ts +22 -0
- package/src/utils/useLocationChange.ts +41 -0
- package/src/utils/usePluralForm.ts +131 -0
- package/src/utils/useThemeConfig.ts +147 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, {
|
|
9
|
+
useState,
|
|
10
|
+
useEffect,
|
|
11
|
+
useCallback,
|
|
12
|
+
useMemo,
|
|
13
|
+
useContext,
|
|
14
|
+
type ReactNode,
|
|
15
|
+
} from 'react';
|
|
16
|
+
import useIsBrowser from '@docusaurus/useIsBrowser';
|
|
17
|
+
import {createStorageSlot} from '../utils/storageUtils';
|
|
18
|
+
import {ReactContextError} from '../utils/reactUtils';
|
|
19
|
+
import {useThemeConfig} from '../utils/useThemeConfig';
|
|
20
|
+
|
|
21
|
+
// Keep these keys in sync with the inlined script
|
|
22
|
+
// See packages/docusaurus-theme-classic/src/inlineScripts.ts
|
|
23
|
+
const AnnouncementBarDismissStorage = createStorageSlot(
|
|
24
|
+
'docusaurus.announcement.dismiss',
|
|
25
|
+
);
|
|
26
|
+
const IdStorage = createStorageSlot('docusaurus.announcement.id');
|
|
27
|
+
|
|
28
|
+
const isDismissedInStorage = () =>
|
|
29
|
+
AnnouncementBarDismissStorage.get() === 'true';
|
|
30
|
+
const setDismissedInStorage = (bool: boolean) =>
|
|
31
|
+
AnnouncementBarDismissStorage.set(String(bool));
|
|
32
|
+
|
|
33
|
+
type ContextValue = {
|
|
34
|
+
/** Whether the announcement bar should be displayed. */
|
|
35
|
+
readonly isActive: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Callback fired when the user closes the announcement. Will be saved.
|
|
38
|
+
*/
|
|
39
|
+
readonly close: () => void;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const Context = React.createContext<ContextValue | null>(null);
|
|
43
|
+
|
|
44
|
+
function useContextValue(): ContextValue {
|
|
45
|
+
const {announcementBar} = useThemeConfig();
|
|
46
|
+
const isBrowser = useIsBrowser();
|
|
47
|
+
|
|
48
|
+
const [isClosed, setClosed] = useState(() =>
|
|
49
|
+
isBrowser
|
|
50
|
+
? // On client navigation: init with local storage value
|
|
51
|
+
isDismissedInStorage()
|
|
52
|
+
: // On server/hydration: always visible to prevent layout shifts (will be hidden with css if needed)
|
|
53
|
+
false,
|
|
54
|
+
);
|
|
55
|
+
// Update state after hydration
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
setClosed(isDismissedInStorage());
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
const handleClose = useCallback(() => {
|
|
61
|
+
setDismissedInStorage(true);
|
|
62
|
+
setClosed(true);
|
|
63
|
+
}, []);
|
|
64
|
+
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!announcementBar) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const {id} = announcementBar;
|
|
70
|
+
|
|
71
|
+
let viewedId = IdStorage.get();
|
|
72
|
+
|
|
73
|
+
// Retrocompatibility due to spelling mistake of default id
|
|
74
|
+
// see https://github.com/facebook/docusaurus/issues/3338
|
|
75
|
+
// cSpell:ignore annoucement
|
|
76
|
+
if (viewedId === 'annoucement-bar') {
|
|
77
|
+
viewedId = 'announcement-bar';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const isNewAnnouncement = id !== viewedId;
|
|
81
|
+
|
|
82
|
+
IdStorage.set(id);
|
|
83
|
+
|
|
84
|
+
if (isNewAnnouncement) {
|
|
85
|
+
setDismissedInStorage(false);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (isNewAnnouncement || !isDismissedInStorage()) {
|
|
89
|
+
setClosed(false);
|
|
90
|
+
}
|
|
91
|
+
}, [announcementBar]);
|
|
92
|
+
|
|
93
|
+
return useMemo(
|
|
94
|
+
() => ({
|
|
95
|
+
isActive: !!announcementBar && !isClosed,
|
|
96
|
+
close: handleClose,
|
|
97
|
+
}),
|
|
98
|
+
[announcementBar, isClosed, handleClose],
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function AnnouncementBarProvider({
|
|
103
|
+
children,
|
|
104
|
+
}: {
|
|
105
|
+
children: ReactNode;
|
|
106
|
+
}): ReactNode {
|
|
107
|
+
const value = useContextValue();
|
|
108
|
+
return <Context value={value}>{children}</Context>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function useAnnouncementBar(): ContextValue {
|
|
112
|
+
const api = useContext(Context);
|
|
113
|
+
if (!api) {
|
|
114
|
+
throw new ReactContextError('AnnouncementBarProvider');
|
|
115
|
+
}
|
|
116
|
+
return api;
|
|
117
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, {
|
|
9
|
+
useState,
|
|
10
|
+
useCallback,
|
|
11
|
+
useEffect,
|
|
12
|
+
useContext,
|
|
13
|
+
useMemo,
|
|
14
|
+
type ReactNode,
|
|
15
|
+
} from 'react';
|
|
16
|
+
import useIsBrowser from '@docusaurus/useIsBrowser';
|
|
17
|
+
import {ReactContextError} from '../utils/reactUtils';
|
|
18
|
+
import {createStorageSlot} from '../utils/storageUtils';
|
|
19
|
+
import {useThemeConfig} from '../utils/useThemeConfig';
|
|
20
|
+
|
|
21
|
+
// The "effective" color mode
|
|
22
|
+
export type ColorMode = 'light' | 'dark';
|
|
23
|
+
|
|
24
|
+
// The color mode explicitly chosen by the user
|
|
25
|
+
// null => no choice has been made, or the choice has been reverted to OS value
|
|
26
|
+
type ColorModeChoice = ColorMode | null;
|
|
27
|
+
|
|
28
|
+
function getSystemColorMode(): ColorMode {
|
|
29
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
30
|
+
? 'dark'
|
|
31
|
+
: 'light';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function subscribeToMedia(
|
|
35
|
+
query: string,
|
|
36
|
+
listener: (event: MediaQueryListEvent) => void,
|
|
37
|
+
): () => void {
|
|
38
|
+
const mql = window.matchMedia(query);
|
|
39
|
+
mql.addEventListener('change', listener);
|
|
40
|
+
return () => mql.removeEventListener('change', listener);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function subscribeToSystemColorModeChange(
|
|
44
|
+
onChange: (newSystemColorMode: ColorMode) => void,
|
|
45
|
+
): () => void {
|
|
46
|
+
return subscribeToMedia('(prefers-color-scheme: dark)', () =>
|
|
47
|
+
onChange(getSystemColorMode()),
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
type ContextValue = {
|
|
52
|
+
/** The effective color mode. */
|
|
53
|
+
readonly colorMode: ColorMode;
|
|
54
|
+
/** The explicitly chosen color mode */
|
|
55
|
+
readonly colorModeChoice: ColorModeChoice;
|
|
56
|
+
/** Set new color mode. */
|
|
57
|
+
readonly setColorMode: (colorMode: ColorModeChoice) => void;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const Context = React.createContext<ContextValue | undefined>(undefined);
|
|
61
|
+
|
|
62
|
+
const ColorModeStorageKey = 'theme';
|
|
63
|
+
const ColorModeStorage = createStorageSlot(ColorModeStorageKey);
|
|
64
|
+
|
|
65
|
+
// We use data-theme-choice="system", not an absent attribute
|
|
66
|
+
// This is easier to handle for users with CSS
|
|
67
|
+
const SystemAttribute = 'system';
|
|
68
|
+
|
|
69
|
+
// Ensure to always return a valid colorMode even if input is invalid
|
|
70
|
+
const coerceToColorMode = (colorMode: string | null): ColorMode =>
|
|
71
|
+
colorMode === 'dark' ? 'dark' : 'light';
|
|
72
|
+
const coerceToColorModeChoice = (colorMode: string | null): ColorModeChoice =>
|
|
73
|
+
colorMode === null || colorMode === SystemAttribute
|
|
74
|
+
? null
|
|
75
|
+
: coerceToColorMode(colorMode);
|
|
76
|
+
|
|
77
|
+
const ColorModeAttribute = {
|
|
78
|
+
get: () => {
|
|
79
|
+
return coerceToColorMode(
|
|
80
|
+
document.documentElement.getAttribute('data-theme'),
|
|
81
|
+
);
|
|
82
|
+
},
|
|
83
|
+
set: (colorMode: ColorMode) => {
|
|
84
|
+
document.documentElement.setAttribute(
|
|
85
|
+
'data-theme',
|
|
86
|
+
coerceToColorMode(colorMode),
|
|
87
|
+
);
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const ColorModeChoiceAttribute = {
|
|
92
|
+
get: () => {
|
|
93
|
+
return coerceToColorModeChoice(
|
|
94
|
+
document.documentElement.getAttribute('data-theme-choice'),
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
set: (colorMode: ColorModeChoice) => {
|
|
98
|
+
document.documentElement.setAttribute(
|
|
99
|
+
'data-theme-choice',
|
|
100
|
+
coerceToColorModeChoice(colorMode) ?? SystemAttribute,
|
|
101
|
+
);
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const persistColorModeChoice = (newColorMode: ColorModeChoice) => {
|
|
106
|
+
if (newColorMode === null) {
|
|
107
|
+
ColorModeStorage.del();
|
|
108
|
+
} else {
|
|
109
|
+
ColorModeStorage.set(coerceToColorMode(newColorMode));
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// The color mode state is initialized in useEffect on purpose
|
|
114
|
+
// to avoid a React hydration mismatch errors
|
|
115
|
+
// The useColorMode() hook value lags behind on purpose
|
|
116
|
+
// This helps users avoid hydration mismatch errors in their code
|
|
117
|
+
// See also https://github.com/facebook/docusaurus/issues/7986
|
|
118
|
+
function useColorModeState() {
|
|
119
|
+
const {
|
|
120
|
+
colorMode: {defaultMode},
|
|
121
|
+
} = useThemeConfig();
|
|
122
|
+
const isBrowser = useIsBrowser();
|
|
123
|
+
|
|
124
|
+
// Since the provider may unmount/remount on client navigation, we need to
|
|
125
|
+
// reinitialize the state with the correct values to avoid visual glitches.
|
|
126
|
+
// See also https://github.com/facebook/docusaurus/issues/11399#issuecomment-3279181314
|
|
127
|
+
const [colorMode, setColorModeState] = useState<ColorMode>(
|
|
128
|
+
isBrowser ? ColorModeAttribute.get() : defaultMode,
|
|
129
|
+
);
|
|
130
|
+
const [colorModeChoice, setColorModeChoiceState] = useState<ColorModeChoice>(
|
|
131
|
+
isBrowser ? ColorModeChoiceAttribute.get() : null,
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
setColorModeState(ColorModeAttribute.get());
|
|
136
|
+
setColorModeChoiceState(ColorModeChoiceAttribute.get());
|
|
137
|
+
}, []);
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
colorMode,
|
|
141
|
+
setColorModeState,
|
|
142
|
+
colorModeChoice,
|
|
143
|
+
setColorModeChoiceState,
|
|
144
|
+
} as const;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function useContextValue(): ContextValue {
|
|
148
|
+
const {
|
|
149
|
+
colorMode: {defaultMode, disableSwitch, respectPrefersColorScheme},
|
|
150
|
+
} = useThemeConfig();
|
|
151
|
+
const {
|
|
152
|
+
colorMode,
|
|
153
|
+
setColorModeState,
|
|
154
|
+
colorModeChoice,
|
|
155
|
+
setColorModeChoiceState,
|
|
156
|
+
} = useColorModeState();
|
|
157
|
+
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
// A site is deployed without disableSwitch
|
|
160
|
+
// => User visits the site and has a persisted value
|
|
161
|
+
// => Site later enabled disableSwitch
|
|
162
|
+
// => Clear the previously stored value to apply the site's setting
|
|
163
|
+
if (disableSwitch) {
|
|
164
|
+
ColorModeStorage.del();
|
|
165
|
+
}
|
|
166
|
+
}, [disableSwitch]);
|
|
167
|
+
|
|
168
|
+
const setColorMode = useCallback(
|
|
169
|
+
(
|
|
170
|
+
newColorModeChoice: ColorModeChoice,
|
|
171
|
+
options: {persist?: boolean} = {},
|
|
172
|
+
) => {
|
|
173
|
+
const {persist = true} = options;
|
|
174
|
+
|
|
175
|
+
// Reset to system/default color mode
|
|
176
|
+
if (newColorModeChoice === null) {
|
|
177
|
+
// Set the effective color
|
|
178
|
+
const newColorMode = respectPrefersColorScheme
|
|
179
|
+
? getSystemColorMode()
|
|
180
|
+
: defaultMode;
|
|
181
|
+
ColorModeAttribute.set(newColorMode);
|
|
182
|
+
setColorModeState(newColorMode);
|
|
183
|
+
// Set the chosen color
|
|
184
|
+
ColorModeChoiceAttribute.set(null);
|
|
185
|
+
setColorModeChoiceState(null);
|
|
186
|
+
}
|
|
187
|
+
// Happy case, when an explicit color is provided
|
|
188
|
+
else {
|
|
189
|
+
ColorModeAttribute.set(newColorModeChoice);
|
|
190
|
+
ColorModeChoiceAttribute.set(newColorModeChoice);
|
|
191
|
+
setColorModeState(newColorModeChoice);
|
|
192
|
+
setColorModeChoiceState(newColorModeChoice);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (persist) {
|
|
196
|
+
persistColorModeChoice(newColorModeChoice);
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
[
|
|
200
|
+
setColorModeState,
|
|
201
|
+
setColorModeChoiceState,
|
|
202
|
+
respectPrefersColorScheme,
|
|
203
|
+
defaultMode,
|
|
204
|
+
],
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// Synchronize theme color/choice mode with browser storage
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
return ColorModeStorage.listen((e) => {
|
|
210
|
+
setColorMode(coerceToColorModeChoice(e.newValue));
|
|
211
|
+
});
|
|
212
|
+
}, [setColorMode]);
|
|
213
|
+
|
|
214
|
+
// Synchronize theme color with system color
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
if (colorModeChoice !== null || !respectPrefersColorScheme) {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
return subscribeToSystemColorModeChange((newSystemColorMode) => {
|
|
220
|
+
// Note: we don't use "setColorMode" on purpose
|
|
221
|
+
// The system changes should never be considered an explicit theme choice
|
|
222
|
+
// They only affect the "effective" color, and should never be persisted
|
|
223
|
+
// Note: this listener also fire when printing, see https://github.com/facebook/docusaurus/pull/6490
|
|
224
|
+
setColorModeState(newSystemColorMode);
|
|
225
|
+
ColorModeAttribute.set(newSystemColorMode);
|
|
226
|
+
});
|
|
227
|
+
}, [respectPrefersColorScheme, colorModeChoice, setColorModeState]);
|
|
228
|
+
|
|
229
|
+
return useMemo(
|
|
230
|
+
() => ({
|
|
231
|
+
colorMode,
|
|
232
|
+
colorModeChoice,
|
|
233
|
+
setColorMode,
|
|
234
|
+
}),
|
|
235
|
+
[colorMode, colorModeChoice, setColorMode],
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export function ColorModeProvider({
|
|
240
|
+
children,
|
|
241
|
+
}: {
|
|
242
|
+
children: ReactNode;
|
|
243
|
+
}): ReactNode {
|
|
244
|
+
const value = useContextValue();
|
|
245
|
+
return <Context value={value}>{children}</Context>;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function useColorMode(): ContextValue {
|
|
249
|
+
const context = useContext(Context);
|
|
250
|
+
if (context == null) {
|
|
251
|
+
throw new ReactContextError(
|
|
252
|
+
'ColorModeProvider',
|
|
253
|
+
'Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.',
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
return context;
|
|
257
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, {
|
|
9
|
+
useCallback,
|
|
10
|
+
useEffect,
|
|
11
|
+
useState,
|
|
12
|
+
useMemo,
|
|
13
|
+
type ReactNode,
|
|
14
|
+
} from 'react';
|
|
15
|
+
import {useNavbarSecondaryMenuContent} from './navbarSecondaryMenu/content';
|
|
16
|
+
import {useWindowSize} from '../hooks/useWindowSize';
|
|
17
|
+
import {useHistoryPopHandler} from '../utils/historyUtils';
|
|
18
|
+
import {useThemeConfig} from '../utils/useThemeConfig';
|
|
19
|
+
import {ReactContextError} from '../utils/reactUtils';
|
|
20
|
+
|
|
21
|
+
type ContextValue = {
|
|
22
|
+
/**
|
|
23
|
+
* Mobile sidebar should be disabled in case it's empty, i.e. no secondary
|
|
24
|
+
* menu + no navbar items). If disabled, the toggle button should not be
|
|
25
|
+
* displayed at all.
|
|
26
|
+
*/
|
|
27
|
+
disabled: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Signals whether the actual sidebar should be displayed (contrary to
|
|
30
|
+
* `disabled` which is about the toggle button). Sidebar should not visible
|
|
31
|
+
* until user interaction to avoid SSR rendering.
|
|
32
|
+
*/
|
|
33
|
+
shouldRender: boolean;
|
|
34
|
+
/** The displayed state. Can be toggled with the `toggle` callback. */
|
|
35
|
+
shown: boolean;
|
|
36
|
+
/** Toggle the `shown` attribute. */
|
|
37
|
+
toggle: () => void;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const Context = React.createContext<ContextValue | undefined>(undefined);
|
|
41
|
+
|
|
42
|
+
function useIsNavbarMobileSidebarDisabled() {
|
|
43
|
+
const secondaryMenuContent = useNavbarSecondaryMenuContent();
|
|
44
|
+
const {items} = useThemeConfig().navbar;
|
|
45
|
+
return items.length === 0 && !secondaryMenuContent.component;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function useContextValue(): ContextValue {
|
|
49
|
+
const disabled = useIsNavbarMobileSidebarDisabled();
|
|
50
|
+
const windowSize = useWindowSize();
|
|
51
|
+
|
|
52
|
+
const shouldRender = !disabled && windowSize === 'mobile';
|
|
53
|
+
|
|
54
|
+
const [shown, setShown] = useState(false);
|
|
55
|
+
|
|
56
|
+
const toggle = useCallback(() => {
|
|
57
|
+
setShown((s) => !s);
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (windowSize === 'desktop') {
|
|
62
|
+
setShown(false);
|
|
63
|
+
}
|
|
64
|
+
}, [windowSize]);
|
|
65
|
+
|
|
66
|
+
return useMemo(
|
|
67
|
+
() => ({disabled, shouldRender, toggle, shown}),
|
|
68
|
+
[disabled, shouldRender, toggle, shown],
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// A component hook wrapper enables conditional rendering
|
|
73
|
+
// See reason here: https://github.com/facebook/docusaurus/issues/10988
|
|
74
|
+
function OnHistoryPop({
|
|
75
|
+
handler,
|
|
76
|
+
}: {
|
|
77
|
+
handler: Parameters<typeof useHistoryPopHandler>[0];
|
|
78
|
+
}) {
|
|
79
|
+
useHistoryPopHandler(handler);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function NavbarMobileSidebarProvider({
|
|
84
|
+
children,
|
|
85
|
+
}: {
|
|
86
|
+
children: ReactNode;
|
|
87
|
+
}): ReactNode {
|
|
88
|
+
const value = useContextValue();
|
|
89
|
+
return (
|
|
90
|
+
<>
|
|
91
|
+
{
|
|
92
|
+
// Close mobile sidebar on navigation pop
|
|
93
|
+
// Most likely firing when using the Android back button (but not only)
|
|
94
|
+
// Important: we can only have a single history blocker at a time
|
|
95
|
+
// That's why this needs to be rendered conditionally
|
|
96
|
+
// See bug report https://github.com/facebook/docusaurus/issues/10988
|
|
97
|
+
value.shown && (
|
|
98
|
+
<OnHistoryPop
|
|
99
|
+
handler={() => {
|
|
100
|
+
value.toggle();
|
|
101
|
+
// Prevent pop navigation; seems desirable enough
|
|
102
|
+
// See https://github.com/facebook/docusaurus/pull/5462#issuecomment-911699846
|
|
103
|
+
return false;
|
|
104
|
+
}}
|
|
105
|
+
/>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
<Context value={value}>{children}</Context>
|
|
109
|
+
</>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function useNavbarMobileSidebar(): ContextValue {
|
|
114
|
+
const context = React.useContext(Context);
|
|
115
|
+
if (context === undefined) {
|
|
116
|
+
throw new ReactContextError('NavbarMobileSidebarProvider');
|
|
117
|
+
}
|
|
118
|
+
return context;
|
|
119
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, {
|
|
9
|
+
useState,
|
|
10
|
+
useContext,
|
|
11
|
+
useEffect,
|
|
12
|
+
type ReactNode,
|
|
13
|
+
type ComponentType,
|
|
14
|
+
} from 'react';
|
|
15
|
+
import {ReactContextError, useShallowMemoObject} from '../../utils/reactUtils';
|
|
16
|
+
|
|
17
|
+
// This context represents a "global layout store". A component (usually a
|
|
18
|
+
// layout component) can request filling this store through
|
|
19
|
+
// `NavbarSecondaryMenuFiller`. It doesn't actually control rendering by itself,
|
|
20
|
+
// and this context should be considered internal implementation. The user-
|
|
21
|
+
// facing value comes from `display.tsx`, which takes the `component` and
|
|
22
|
+
// `props` stored here and renders the actual element.
|
|
23
|
+
|
|
24
|
+
export type NavbarSecondaryMenuComponent<Props> = ComponentType<Props>;
|
|
25
|
+
|
|
26
|
+
/** @internal */
|
|
27
|
+
export type Content =
|
|
28
|
+
| {
|
|
29
|
+
component: NavbarSecondaryMenuComponent<object>;
|
|
30
|
+
props: object;
|
|
31
|
+
}
|
|
32
|
+
| {component: null; props: null};
|
|
33
|
+
|
|
34
|
+
type ContextValue = [
|
|
35
|
+
content: Content,
|
|
36
|
+
setContent: React.Dispatch<React.SetStateAction<Content>>,
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const Context = React.createContext<ContextValue | null>(null);
|
|
40
|
+
|
|
41
|
+
/** @internal */
|
|
42
|
+
export function NavbarSecondaryMenuContentProvider({
|
|
43
|
+
children,
|
|
44
|
+
}: {
|
|
45
|
+
children: ReactNode;
|
|
46
|
+
}): ReactNode {
|
|
47
|
+
const value = useState({component: null, props: null});
|
|
48
|
+
return (
|
|
49
|
+
// @ts-expect-error: this context is hard to type
|
|
50
|
+
<Context value={value}>{children}</Context>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** @internal */
|
|
55
|
+
export function useNavbarSecondaryMenuContent(): Content {
|
|
56
|
+
const value = useContext(Context);
|
|
57
|
+
if (!value) {
|
|
58
|
+
throw new ReactContextError('NavbarSecondaryMenuContentProvider');
|
|
59
|
+
}
|
|
60
|
+
return value[0];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* This component renders nothing by itself, but it fills the placeholder in the
|
|
65
|
+
* generic secondary menu layout. This reduces coupling between the main layout
|
|
66
|
+
* and the specific page.
|
|
67
|
+
*
|
|
68
|
+
* This kind of feature is often called portal/teleport/gateway/outlet...
|
|
69
|
+
* Various unmaintained React libs exist. Most up-to-date one:
|
|
70
|
+
* https://github.com/gregberge/react-teleporter
|
|
71
|
+
* Not sure any of those is safe regarding concurrent mode.
|
|
72
|
+
*/
|
|
73
|
+
export function NavbarSecondaryMenuFiller<P extends object>({
|
|
74
|
+
component,
|
|
75
|
+
props,
|
|
76
|
+
}: {
|
|
77
|
+
component: NavbarSecondaryMenuComponent<P>;
|
|
78
|
+
props: P;
|
|
79
|
+
}): ReactNode {
|
|
80
|
+
const context = useContext(Context);
|
|
81
|
+
if (!context) {
|
|
82
|
+
throw new ReactContextError('NavbarSecondaryMenuContentProvider');
|
|
83
|
+
}
|
|
84
|
+
const [, setContent] = context;
|
|
85
|
+
|
|
86
|
+
// To avoid useless context re-renders, props are memoized shallowly
|
|
87
|
+
const memoizedProps = useShallowMemoObject(props);
|
|
88
|
+
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
// @ts-expect-error: this context is hard to type
|
|
91
|
+
setContent({component, props: memoizedProps});
|
|
92
|
+
}, [setContent, component, memoizedProps]);
|
|
93
|
+
|
|
94
|
+
useEffect(
|
|
95
|
+
() => () => setContent({component: null, props: null}),
|
|
96
|
+
[setContent],
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, {
|
|
9
|
+
useState,
|
|
10
|
+
useContext,
|
|
11
|
+
useEffect,
|
|
12
|
+
useMemo,
|
|
13
|
+
useCallback,
|
|
14
|
+
type ReactNode,
|
|
15
|
+
} from 'react';
|
|
16
|
+
import {ReactContextError, usePrevious} from '../../utils/reactUtils';
|
|
17
|
+
import {useNavbarMobileSidebar} from '../navbarMobileSidebar';
|
|
18
|
+
import {useNavbarSecondaryMenuContent, type Content} from './content';
|
|
19
|
+
|
|
20
|
+
type ContextValue = [
|
|
21
|
+
shown: boolean,
|
|
22
|
+
setShown: React.Dispatch<React.SetStateAction<boolean>>,
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const Context = React.createContext<ContextValue | null>(null);
|
|
26
|
+
|
|
27
|
+
function useContextValue(): ContextValue {
|
|
28
|
+
const mobileSidebar = useNavbarMobileSidebar();
|
|
29
|
+
const content = useNavbarSecondaryMenuContent();
|
|
30
|
+
|
|
31
|
+
const [shown, setShown] = useState(false);
|
|
32
|
+
|
|
33
|
+
const hasContent = content.component !== null;
|
|
34
|
+
const previousHasContent = usePrevious(hasContent);
|
|
35
|
+
|
|
36
|
+
// When content is become available for the first time (set in useEffect)
|
|
37
|
+
// we set this content to be shown!
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const contentBecameAvailable = hasContent && !previousHasContent;
|
|
40
|
+
if (contentBecameAvailable) {
|
|
41
|
+
setShown(true);
|
|
42
|
+
}
|
|
43
|
+
}, [hasContent, previousHasContent]);
|
|
44
|
+
|
|
45
|
+
// On sidebar close, secondary menu is set to be shown on next re-opening
|
|
46
|
+
// (if any secondary menu content available)
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (!hasContent) {
|
|
49
|
+
setShown(false);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (!mobileSidebar.shown) {
|
|
53
|
+
setShown(true);
|
|
54
|
+
}
|
|
55
|
+
}, [mobileSidebar.shown, hasContent]);
|
|
56
|
+
|
|
57
|
+
return useMemo(() => [shown, setShown], [shown]);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** @internal */
|
|
61
|
+
export function NavbarSecondaryMenuDisplayProvider({
|
|
62
|
+
children,
|
|
63
|
+
}: {
|
|
64
|
+
children: ReactNode;
|
|
65
|
+
}): ReactNode {
|
|
66
|
+
const value = useContextValue();
|
|
67
|
+
return <Context value={value}>{children}</Context>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function renderElement(content: Content): ReactNode {
|
|
71
|
+
if (content.component) {
|
|
72
|
+
const Comp = content.component;
|
|
73
|
+
return <Comp {...content.props} />;
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Wires the logic for rendering the mobile navbar secondary menu. */
|
|
79
|
+
export function useNavbarSecondaryMenu(): {
|
|
80
|
+
/** Whether secondary menu is displayed. */
|
|
81
|
+
shown: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Hide the secondary menu; fired either when hiding the entire sidebar, or
|
|
84
|
+
* when going back to the primary menu.
|
|
85
|
+
*/
|
|
86
|
+
hide: () => void;
|
|
87
|
+
/** The content returned from the current secondary menu filler. */
|
|
88
|
+
content: ReactNode;
|
|
89
|
+
} {
|
|
90
|
+
const value = useContext(Context);
|
|
91
|
+
if (!value) {
|
|
92
|
+
throw new ReactContextError('NavbarSecondaryMenuDisplayProvider');
|
|
93
|
+
}
|
|
94
|
+
const [shown, setShown] = value;
|
|
95
|
+
const hide = useCallback(() => setShown(false), [setShown]);
|
|
96
|
+
const content = useNavbarSecondaryMenuContent();
|
|
97
|
+
|
|
98
|
+
return useMemo(
|
|
99
|
+
() => ({shown, hide, content: renderElement(content)}),
|
|
100
|
+
[hide, content, shown],
|
|
101
|
+
);
|
|
102
|
+
}
|