@docusaurus/theme-common 2.0.0-beta.17 → 2.0.0-beta.18

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.
Files changed (254) hide show
  1. package/lib/components/Collapsible/index.d.ts +32 -4
  2. package/lib/components/Collapsible/index.d.ts.map +1 -1
  3. package/lib/components/Collapsible/index.js +12 -3
  4. package/lib/components/Collapsible/index.js.map +1 -1
  5. package/lib/components/Details/index.d.ts +6 -1
  6. package/lib/components/Details/index.d.ts.map +1 -1
  7. package/lib/components/Details/index.js +8 -4
  8. package/lib/components/Details/index.js.map +1 -1
  9. package/lib/{utils/announcementBarUtils.d.ts → contexts/announcementBar.d.ts} +7 -3
  10. package/lib/contexts/announcementBar.d.ts.map +1 -0
  11. package/lib/{utils/announcementBarUtils.js → contexts/announcementBar.js} +11 -11
  12. package/lib/contexts/announcementBar.js.map +1 -0
  13. package/lib/{utils/colorModeUtils.d.ts → contexts/colorMode.d.ts} +12 -3
  14. package/lib/contexts/colorMode.d.ts.map +1 -0
  15. package/lib/contexts/colorMode.js +114 -0
  16. package/lib/contexts/colorMode.js.map +1 -0
  17. package/lib/contexts/docSidebarItemsExpandedState.d.ts +31 -0
  18. package/lib/contexts/docSidebarItemsExpandedState.d.ts.map +1 -0
  19. package/lib/{utils → contexts}/docSidebarItemsExpandedState.js +9 -4
  20. package/lib/contexts/docSidebarItemsExpandedState.js.map +1 -0
  21. package/lib/contexts/docsPreferredVersion.d.ts +28 -0
  22. package/lib/contexts/docsPreferredVersion.d.ts.map +1 -0
  23. package/lib/contexts/docsPreferredVersion.js +125 -0
  24. package/lib/contexts/docsPreferredVersion.js.map +1 -0
  25. package/lib/contexts/docsSidebar.d.ts +20 -0
  26. package/lib/contexts/docsSidebar.d.ts.map +1 -0
  27. package/lib/contexts/docsSidebar.js +29 -0
  28. package/lib/contexts/docsSidebar.js.map +1 -0
  29. package/lib/contexts/docsVersion.d.ts +20 -0
  30. package/lib/contexts/docsVersion.d.ts.map +1 -0
  31. package/lib/contexts/docsVersion.js +26 -0
  32. package/lib/contexts/docsVersion.js.map +1 -0
  33. package/lib/contexts/navbarMobileSidebar.d.ts +31 -0
  34. package/lib/contexts/navbarMobileSidebar.d.ts.map +1 -0
  35. package/lib/contexts/navbarMobileSidebar.js +56 -0
  36. package/lib/contexts/navbarMobileSidebar.js.map +1 -0
  37. package/lib/contexts/navbarSecondaryMenu.d.ts +38 -0
  38. package/lib/contexts/navbarSecondaryMenu.d.ts.map +1 -0
  39. package/lib/contexts/navbarSecondaryMenu.js +93 -0
  40. package/lib/contexts/navbarSecondaryMenu.js.map +1 -0
  41. package/lib/{utils/tabGroupChoiceUtils.d.ts → contexts/tabGroupChoice.d.ts} +5 -3
  42. package/lib/contexts/tabGroupChoice.d.ts.map +1 -0
  43. package/lib/{utils/tabGroupChoiceUtils.js → contexts/tabGroupChoice.js} +14 -20
  44. package/lib/contexts/tabGroupChoice.js.map +1 -0
  45. package/lib/hooks/useHideableNavbar.d.ts +7 -3
  46. package/lib/hooks/useHideableNavbar.d.ts.map +1 -1
  47. package/lib/hooks/useHideableNavbar.js +8 -6
  48. package/lib/hooks/useHideableNavbar.js.map +1 -1
  49. package/lib/hooks/useKeyboardNavigation.d.ts +11 -1
  50. package/lib/hooks/useKeyboardNavigation.d.ts.map +1 -1
  51. package/lib/hooks/useKeyboardNavigation.js +11 -3
  52. package/lib/hooks/useKeyboardNavigation.js.map +1 -1
  53. package/lib/hooks/useLockBodyScroll.d.ts +5 -1
  54. package/lib/hooks/useLockBodyScroll.d.ts.map +1 -1
  55. package/lib/hooks/useLockBodyScroll.js +5 -1
  56. package/lib/hooks/useLockBodyScroll.js.map +1 -1
  57. package/lib/hooks/usePrismTheme.d.ts +5 -1
  58. package/lib/hooks/usePrismTheme.d.ts.map +1 -1
  59. package/lib/hooks/usePrismTheme.js +8 -4
  60. package/lib/hooks/usePrismTheme.js.map +1 -1
  61. package/lib/hooks/useSearchPage.d.ts +15 -4
  62. package/lib/hooks/useSearchPage.d.ts.map +1 -1
  63. package/lib/hooks/useSearchPage.js +3 -2
  64. package/lib/hooks/useSearchPage.js.map +1 -1
  65. package/lib/hooks/useTOCHighlight.d.ts +25 -0
  66. package/lib/hooks/useTOCHighlight.d.ts.map +1 -0
  67. package/lib/{utils → hooks}/useTOCHighlight.js +13 -9
  68. package/lib/hooks/useTOCHighlight.js.map +1 -0
  69. package/lib/hooks/useWindowSize.d.ts +14 -1
  70. package/lib/hooks/useWindowSize.d.ts.map +1 -1
  71. package/lib/hooks/useWindowSize.js +14 -11
  72. package/lib/hooks/useWindowSize.js.map +1 -1
  73. package/lib/index.d.ts +26 -30
  74. package/lib/index.d.ts.map +1 -1
  75. package/lib/index.js +26 -24
  76. package/lib/index.js.map +1 -1
  77. package/lib/utils/ThemeClassNames.d.ts +7 -0
  78. package/lib/utils/ThemeClassNames.d.ts.map +1 -1
  79. package/lib/utils/ThemeClassNames.js +7 -4
  80. package/lib/utils/ThemeClassNames.js.map +1 -1
  81. package/lib/utils/codeBlockUtils.d.ts +25 -2
  82. package/lib/utils/codeBlockUtils.d.ts.map +1 -1
  83. package/lib/utils/codeBlockUtils.js +36 -35
  84. package/lib/utils/codeBlockUtils.js.map +1 -1
  85. package/lib/utils/docsUtils.d.ts +25 -18
  86. package/lib/utils/docsUtils.d.ts.map +1 -1
  87. package/lib/utils/docsUtils.js +38 -56
  88. package/lib/utils/docsUtils.js.map +1 -1
  89. package/lib/utils/footerUtils.d.ts +13 -0
  90. package/lib/utils/footerUtils.d.ts.map +1 -0
  91. package/lib/utils/footerUtils.js +14 -0
  92. package/lib/utils/footerUtils.js.map +1 -0
  93. package/lib/utils/generalUtils.d.ts +4 -1
  94. package/lib/utils/generalUtils.d.ts.map +1 -1
  95. package/lib/utils/generalUtils.js +6 -3
  96. package/lib/utils/generalUtils.js.map +1 -1
  97. package/lib/utils/historyUtils.d.ts +1 -7
  98. package/lib/utils/historyUtils.d.ts.map +1 -1
  99. package/lib/utils/historyUtils.js +10 -13
  100. package/lib/utils/historyUtils.js.map +1 -1
  101. package/lib/utils/jsUtils.d.ts +1 -1
  102. package/lib/utils/jsUtils.js +1 -1
  103. package/lib/utils/metadataUtils.d.ts +38 -0
  104. package/lib/utils/metadataUtils.d.ts.map +1 -0
  105. package/lib/utils/metadataUtils.js +61 -0
  106. package/lib/utils/metadataUtils.js.map +1 -0
  107. package/lib/utils/navbarUtils.d.ts +21 -0
  108. package/lib/utils/navbarUtils.d.ts.map +1 -0
  109. package/lib/utils/navbarUtils.js +30 -0
  110. package/lib/utils/navbarUtils.js.map +1 -0
  111. package/lib/utils/reactUtils.d.ts +16 -5
  112. package/lib/utils/reactUtils.d.ts.map +1 -1
  113. package/lib/utils/reactUtils.js +28 -7
  114. package/lib/utils/reactUtils.js.map +1 -1
  115. package/lib/utils/regexpUtils.d.ts +2 -1
  116. package/lib/utils/regexpUtils.d.ts.map +1 -1
  117. package/lib/utils/regexpUtils.js +2 -1
  118. package/lib/utils/regexpUtils.js.map +1 -1
  119. package/lib/utils/routesUtils.d.ts +14 -2
  120. package/lib/utils/routesUtils.d.ts.map +1 -1
  121. package/lib/utils/routesUtils.js +20 -7
  122. package/lib/utils/routesUtils.js.map +1 -1
  123. package/lib/utils/scrollUtils.d.ts +32 -26
  124. package/lib/utils/scrollUtils.d.ts.map +1 -1
  125. package/lib/utils/scrollUtils.js +30 -17
  126. package/lib/utils/scrollUtils.js.map +1 -1
  127. package/lib/utils/searchUtils.d.ts +12 -0
  128. package/lib/utils/searchUtils.d.ts.map +1 -1
  129. package/lib/utils/searchUtils.js +34 -0
  130. package/lib/utils/searchUtils.js.map +1 -1
  131. package/lib/utils/storageUtils.d.ts +10 -7
  132. package/lib/utils/storageUtils.d.ts.map +1 -1
  133. package/lib/utils/storageUtils.js +20 -12
  134. package/lib/utils/storageUtils.js.map +1 -1
  135. package/lib/utils/tagsUtils.d.ts +5 -2
  136. package/lib/utils/tagsUtils.d.ts.map +1 -1
  137. package/lib/utils/tagsUtils.js +7 -4
  138. package/lib/utils/tagsUtils.js.map +1 -1
  139. package/lib/utils/tocUtils.d.ts +16 -0
  140. package/lib/utils/tocUtils.d.ts.map +1 -1
  141. package/lib/utils/tocUtils.js +17 -6
  142. package/lib/utils/tocUtils.js.map +1 -1
  143. package/lib/utils/useAlternatePageUtils.d.ts +20 -1
  144. package/lib/utils/useAlternatePageUtils.d.ts.map +1 -1
  145. package/lib/utils/useAlternatePageUtils.js +6 -3
  146. package/lib/utils/useAlternatePageUtils.js.map +1 -1
  147. package/lib/utils/useLocalPathname.d.ts +5 -0
  148. package/lib/utils/useLocalPathname.d.ts.map +1 -1
  149. package/lib/utils/useLocalPathname.js +6 -4
  150. package/lib/utils/useLocalPathname.js.map +1 -1
  151. package/lib/utils/useLocationChange.d.ts +7 -5
  152. package/lib/utils/useLocationChange.d.ts.map +1 -1
  153. package/lib/utils/useLocationChange.js +6 -2
  154. package/lib/utils/useLocationChange.js.map +1 -1
  155. package/lib/utils/usePluralForm.d.ts +11 -0
  156. package/lib/utils/usePluralForm.d.ts.map +1 -1
  157. package/lib/utils/usePluralForm.js +19 -24
  158. package/lib/utils/usePluralForm.js.map +1 -1
  159. package/lib/utils/useThemeConfig.d.ts +21 -11
  160. package/lib/utils/useThemeConfig.d.ts.map +1 -1
  161. package/lib/utils/useThemeConfig.js +3 -0
  162. package/lib/utils/useThemeConfig.js.map +1 -1
  163. package/package.json +8 -9
  164. package/src/components/Collapsible/index.tsx +40 -22
  165. package/src/components/Details/index.tsx +11 -6
  166. package/src/{utils/announcementBarUtils.tsx → contexts/announcementBar.tsx} +17 -18
  167. package/src/contexts/colorMode.tsx +176 -0
  168. package/src/contexts/docSidebarItemsExpandedState.tsx +55 -0
  169. package/src/contexts/docsPreferredVersion.tsx +250 -0
  170. package/src/contexts/docsSidebar.tsx +42 -0
  171. package/src/contexts/docsVersion.tsx +36 -0
  172. package/src/contexts/navbarMobileSidebar.tsx +99 -0
  173. package/src/contexts/navbarSecondaryMenu.tsx +170 -0
  174. package/src/{utils/tabGroupChoiceUtils.tsx → contexts/tabGroupChoice.tsx} +21 -28
  175. package/src/hooks/useHideableNavbar.ts +11 -11
  176. package/src/hooks/useKeyboardNavigation.ts +11 -3
  177. package/src/hooks/useLockBodyScroll.ts +5 -2
  178. package/src/hooks/usePrismTheme.ts +8 -4
  179. package/src/hooks/useSearchPage.ts +18 -5
  180. package/src/{utils → hooks}/useTOCHighlight.ts +21 -12
  181. package/src/hooks/useWindowSize.ts +14 -12
  182. package/src/index.ts +68 -56
  183. package/src/utils/ThemeClassNames.ts +10 -6
  184. package/src/utils/codeBlockUtils.ts +49 -47
  185. package/src/utils/docsUtils.tsx +48 -99
  186. package/src/utils/footerUtils.ts +18 -0
  187. package/src/utils/generalUtils.ts +6 -3
  188. package/src/utils/historyUtils.ts +11 -17
  189. package/src/utils/jsUtils.ts +1 -1
  190. package/src/utils/metadataUtils.tsx +115 -0
  191. package/src/utils/navbarUtils.tsx +40 -0
  192. package/src/utils/reactUtils.tsx +31 -8
  193. package/src/utils/regexpUtils.ts +2 -1
  194. package/src/utils/routesUtils.ts +27 -8
  195. package/src/utils/scrollUtils.tsx +44 -45
  196. package/src/utils/searchUtils.ts +49 -0
  197. package/src/utils/storageUtils.ts +21 -13
  198. package/src/utils/tagsUtils.ts +14 -7
  199. package/src/utils/tocUtils.ts +18 -7
  200. package/src/utils/useAlternatePageUtils.ts +17 -5
  201. package/src/utils/useLocalPathname.ts +6 -4
  202. package/src/utils/useLocationChange.ts +12 -10
  203. package/src/utils/usePluralForm.ts +27 -24
  204. package/src/utils/useThemeConfig.ts +16 -11
  205. package/lib/utils/announcementBarUtils.d.ts.map +0 -1
  206. package/lib/utils/announcementBarUtils.js.map +0 -1
  207. package/lib/utils/colorModeUtils.d.ts.map +0 -1
  208. package/lib/utils/colorModeUtils.js +0 -107
  209. package/lib/utils/colorModeUtils.js.map +0 -1
  210. package/lib/utils/docSidebarItemsExpandedState.d.ts +0 -17
  211. package/lib/utils/docSidebarItemsExpandedState.d.ts.map +0 -1
  212. package/lib/utils/docSidebarItemsExpandedState.js.map +0 -1
  213. package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.d.ts +0 -22
  214. package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.d.ts.map +0 -1
  215. package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.js +0 -92
  216. package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.js.map +0 -1
  217. package/lib/utils/docsPreferredVersion/DocsPreferredVersionStorage.d.ts +0 -14
  218. package/lib/utils/docsPreferredVersion/DocsPreferredVersionStorage.d.ts.map +0 -1
  219. package/lib/utils/docsPreferredVersion/DocsPreferredVersionStorage.js +0 -19
  220. package/lib/utils/docsPreferredVersion/DocsPreferredVersionStorage.js.map +0 -1
  221. package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.d.ts +0 -14
  222. package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.d.ts.map +0 -1
  223. package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.js +0 -41
  224. package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.js.map +0 -1
  225. package/lib/utils/mobileSecondaryMenu.d.ts +0 -21
  226. package/lib/utils/mobileSecondaryMenu.d.ts.map +0 -1
  227. package/lib/utils/mobileSecondaryMenu.js +0 -51
  228. package/lib/utils/mobileSecondaryMenu.js.map +0 -1
  229. package/lib/utils/pathUtils.d.ts +0 -8
  230. package/lib/utils/pathUtils.d.ts.map +0 -1
  231. package/lib/utils/pathUtils.js +0 -14
  232. package/lib/utils/pathUtils.js.map +0 -1
  233. package/lib/utils/tabGroupChoiceUtils.d.ts.map +0 -1
  234. package/lib/utils/tabGroupChoiceUtils.js.map +0 -1
  235. package/lib/utils/useContextualSearchFilters.d.ts +0 -12
  236. package/lib/utils/useContextualSearchFilters.d.ts.map +0 -1
  237. package/lib/utils/useContextualSearchFilters.js +0 -36
  238. package/lib/utils/useContextualSearchFilters.js.map +0 -1
  239. package/lib/utils/usePrevious.d.ts +0 -8
  240. package/lib/utils/usePrevious.d.ts.map +0 -1
  241. package/lib/utils/usePrevious.js +0 -16
  242. package/lib/utils/usePrevious.js.map +0 -1
  243. package/lib/utils/useTOCHighlight.d.ts +0 -14
  244. package/lib/utils/useTOCHighlight.d.ts.map +0 -1
  245. package/lib/utils/useTOCHighlight.js.map +0 -1
  246. package/src/utils/colorModeUtils.tsx +0 -158
  247. package/src/utils/docSidebarItemsExpandedState.tsx +0 -40
  248. package/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx +0 -166
  249. package/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts +0 -33
  250. package/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts +0 -70
  251. package/src/utils/mobileSecondaryMenu.tsx +0 -114
  252. package/src/utils/pathUtils.ts +0 -19
  253. package/src/utils/useContextualSearchFilters.ts +0 -53
  254. package/src/utils/usePrevious.ts +0 -19
@@ -5,57 +5,32 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import React, {createContext, type ReactNode, useContext} from 'react';
9
8
  import {
10
- useActivePlugin,
11
9
  useAllDocsData,
10
+ useActivePlugin,
12
11
  } from '@docusaurus/plugin-content-docs/client';
13
12
  import type {
14
13
  PropSidebar,
15
14
  PropSidebarItem,
16
15
  PropSidebarItemCategory,
17
16
  PropVersionDoc,
18
- PropVersionMetadata,
19
17
  PropSidebarBreadcrumbsItem,
20
18
  } from '@docusaurus/plugin-content-docs';
21
- import {isSamePath} from './pathUtils';
22
- import {ReactContextError} from './reactUtils';
19
+ import {useDocsVersion} from '../contexts/docsVersion';
20
+ import {useDocsSidebar} from '../contexts/docsSidebar';
21
+ import {isSamePath} from './routesUtils';
23
22
  import {useLocation} from '@docusaurus/router';
24
23
 
25
24
  // TODO not ideal, see also "useDocs"
26
25
  export const isDocsPluginEnabled: boolean = !!useAllDocsData;
27
26
 
28
- // Using a Symbol because null is a valid context value (a doc with no sidebar)
29
- // Inspired by https://github.com/jamiebuilds/unstated-next/blob/master/src/unstated-next.tsx
30
- const EmptyContextValue: unique symbol = Symbol('EmptyContext');
31
-
32
- const DocsVersionContext = createContext<
33
- PropVersionMetadata | typeof EmptyContextValue
34
- >(EmptyContextValue);
35
-
36
- export function DocsVersionProvider({
37
- children,
38
- version,
39
- }: {
40
- children: ReactNode;
41
- version: PropVersionMetadata | typeof EmptyContextValue;
42
- }): JSX.Element {
43
- return (
44
- <DocsVersionContext.Provider value={version}>
45
- {children}
46
- </DocsVersionContext.Provider>
47
- );
48
- }
49
-
50
- export function useDocsVersion(): PropVersionMetadata {
51
- const version = useContext(DocsVersionContext);
52
- if (version === EmptyContextValue) {
53
- throw new ReactContextError('DocsVersionProvider');
54
- }
55
- return version;
56
- }
57
-
27
+ /**
28
+ * A null-safe way to access a doc's data by ID in the active version.
29
+ */
58
30
  export function useDocById(id: string): PropVersionDoc;
31
+ /**
32
+ * A null-safe way to access a doc's data by ID in the active version.
33
+ */
59
34
  export function useDocById(id: string | undefined): PropVersionDoc | undefined;
60
35
  export function useDocById(id: string | undefined): PropVersionDoc | undefined {
61
36
  const version = useDocsVersion();
@@ -69,34 +44,9 @@ export function useDocById(id: string | undefined): PropVersionDoc | undefined {
69
44
  return doc;
70
45
  }
71
46
 
72
- const DocsSidebarContext = createContext<
73
- PropSidebar | null | typeof EmptyContextValue
74
- >(EmptyContextValue);
75
-
76
- export function DocsSidebarProvider({
77
- children,
78
- sidebar,
79
- }: {
80
- children: ReactNode;
81
- sidebar: PropSidebar | null;
82
- }): JSX.Element {
83
- return (
84
- <DocsSidebarContext.Provider value={sidebar}>
85
- {children}
86
- </DocsSidebarContext.Provider>
87
- );
88
- }
89
-
90
- export function useDocsSidebar(): PropSidebar | null {
91
- const sidebar = useContext(DocsSidebarContext);
92
- if (sidebar === EmptyContextValue) {
93
- throw new ReactContextError('DocsSidebarProvider');
94
- }
95
- return sidebar;
96
- }
97
-
98
- // Use the components props and the sidebar in context
99
- // to get back the related sidebar category that we want to render
47
+ /**
48
+ * Pure function, similar to `Array#find`, but works on the sidebar tree.
49
+ */
100
50
  export function findSidebarCategory(
101
51
  sidebar: PropSidebar,
102
52
  predicate: (category: PropSidebarItemCategory) => boolean,
@@ -115,7 +65,10 @@ export function findSidebarCategory(
115
65
  return undefined;
116
66
  }
117
67
 
118
- // If a category card has no link => link to the first subItem having a link
68
+ /**
69
+ * Best effort to assign a link to a sidebar category. If the category doesn't
70
+ * have a link itself, we link to the first sub item with a link.
71
+ */
119
72
  export function findFirstCategoryLink(
120
73
  item: PropSidebarItemCategory,
121
74
  ): string | undefined {
@@ -142,6 +95,10 @@ export function findFirstCategoryLink(
142
95
  return undefined;
143
96
  }
144
97
 
98
+ /**
99
+ * Gets the category associated with the current location. Should only be used
100
+ * on category index pages.
101
+ */
145
102
  export function useCurrentSidebarCategory(): PropSidebarItemCategory {
146
103
  const {pathname} = useLocation();
147
104
  const sidebar = useDocsSidebar();
@@ -153,60 +110,64 @@ export function useCurrentSidebarCategory(): PropSidebarItemCategory {
153
110
  );
154
111
  if (!category) {
155
112
  throw new Error(
156
- `Unexpected: sidebar category could not be found for pathname='${pathname}'.
157
- Hook useCurrentSidebarCategory() should only be used on Category pages`,
113
+ `${pathname} is not associated with a category. useCurrentSidebarCategory() should only be used on category index pages.`,
158
114
  );
159
115
  }
160
116
  return category;
161
117
  }
162
118
 
163
- function containsActiveSidebarItem(
119
+ const isActive = (testedPath: string | undefined, activePath: string) =>
120
+ typeof testedPath !== 'undefined' && isSamePath(testedPath, activePath);
121
+ const containsActiveSidebarItem = (
164
122
  items: PropSidebarItem[],
165
123
  activePath: string,
166
- ): boolean {
167
- return items.some((subItem) => isActiveSidebarItem(subItem, activePath));
168
- }
124
+ ) => items.some((subItem) => isActiveSidebarItem(subItem, activePath));
169
125
 
126
+ /**
127
+ * Checks if a sidebar item should be active, based on the active path.
128
+ */
170
129
  export function isActiveSidebarItem(
171
130
  item: PropSidebarItem,
172
131
  activePath: string,
173
132
  ): boolean {
174
- const isActive = (testedPath: string | undefined) =>
175
- typeof testedPath !== 'undefined' && isSamePath(testedPath, activePath);
176
-
177
133
  if (item.type === 'link') {
178
- return isActive(item.href);
134
+ return isActive(item.href, activePath);
179
135
  }
180
136
 
181
137
  if (item.type === 'category') {
182
138
  return (
183
- isActive(item.href) || containsActiveSidebarItem(item.items, activePath)
139
+ isActive(item.href, activePath) ||
140
+ containsActiveSidebarItem(item.items, activePath)
184
141
  );
185
142
  }
186
143
 
187
144
  return false;
188
145
  }
189
146
 
190
- export function getBreadcrumbs({
191
- sidebar,
192
- pathname,
193
- }: {
194
- sidebar: PropSidebar;
195
- pathname: string;
196
- }): PropSidebarBreadcrumbsItem[] {
147
+ /**
148
+ * Gets the breadcrumbs of the current doc page, based on its sidebar location.
149
+ * Returns `null` if there's no sidebar or breadcrumbs are disabled.
150
+ */
151
+ export function useSidebarBreadcrumbs(): PropSidebarBreadcrumbsItem[] | null {
152
+ const sidebar = useDocsSidebar();
153
+ const {pathname} = useLocation();
154
+ const breadcrumbsOption = useActivePlugin()?.pluginData.breadcrumbs;
155
+
156
+ if (breadcrumbsOption === false || !sidebar) {
157
+ return null;
158
+ }
159
+
197
160
  const breadcrumbs: PropSidebarBreadcrumbsItem[] = [];
198
161
 
199
162
  function extract(items: PropSidebar) {
200
163
  for (const item of items) {
201
164
  if (
202
- item.type === 'category' &&
203
- (isSamePath(item.href, pathname) || extract(item.items))
165
+ (item.type === 'category' &&
166
+ (isSamePath(item.href, pathname) || extract(item.items))) ||
167
+ (item.type === 'link' && isSamePath(item.href, pathname))
204
168
  ) {
205
169
  breadcrumbs.push(item);
206
170
  return true;
207
- } else if (item.type === 'link' && isSamePath(item.href, pathname)) {
208
- breadcrumbs.push(item);
209
- return true;
210
171
  }
211
172
  }
212
173
 
@@ -217,15 +178,3 @@ export function getBreadcrumbs({
217
178
 
218
179
  return breadcrumbs.reverse();
219
180
  }
220
-
221
- export function useSidebarBreadcrumbs(): PropSidebarBreadcrumbsItem[] | null {
222
- const sidebar = useDocsSidebar();
223
- const {pathname} = useLocation();
224
- const breadcrumbsOption = useActivePlugin()?.pluginData.breadcrumbs;
225
-
226
- if (breadcrumbsOption === false || !sidebar) {
227
- return null;
228
- }
229
-
230
- return getBreadcrumbs({sidebar, pathname});
231
- }
@@ -0,0 +1,18 @@
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 type {MultiColumnFooter, SimpleFooter} from './useThemeConfig';
9
+
10
+ /**
11
+ * A rough duck-typing about whether the `footer.links` is intended to be multi-
12
+ * column.
13
+ */
14
+ export function isMultiColumnFooterLinks(
15
+ links: MultiColumnFooter['links'] | SimpleFooter['links'],
16
+ ): links is MultiColumnFooter['links'] {
17
+ return 'title' in links[0]!;
18
+ }
@@ -7,10 +7,13 @@
7
7
 
8
8
  import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
9
9
 
10
- export const useTitleFormatter = (title?: string | undefined): string => {
10
+ /**
11
+ * Formats the page's title based on relevant site config and other contexts.
12
+ */
13
+ export function useTitleFormatter(title?: string | undefined): string {
11
14
  const {siteConfig} = useDocusaurusContext();
12
15
  const {title: siteTitle, titleDelimiter} = siteConfig;
13
- return title && title.trim().length
16
+ return title?.trim().length
14
17
  ? `${title.trim()} ${titleDelimiter} ${siteTitle}`
15
18
  : siteTitle;
16
- };
19
+ }
@@ -5,44 +5,38 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import {useEffect, useRef} from 'react';
8
+ import {useEffect} from 'react';
9
9
  import {useHistory} from '@docusaurus/router';
10
+ import {useDynamicCallback} from './reactUtils';
10
11
  import type {Location, Action} from 'history';
11
12
 
12
13
  type HistoryBlockHandler = (location: Location, action: Action) => void | false;
13
14
 
14
15
  /**
15
16
  * Permits to register a handler that will be called on history actions (pop,
16
- * push, replace) If the handler returns false, the navigation transition will
17
- * be blocked/cancelled
17
+ * push, replace). If the handler returns `false`, the navigation transition
18
+ * will be blocked/cancelled.
18
19
  */
19
- export function useHistoryActionHandler(handler: HistoryBlockHandler): void {
20
+ function useHistoryActionHandler(handler: HistoryBlockHandler): void {
20
21
  const {block} = useHistory();
21
-
22
- // Avoid stale closure issues without triggering useless re-renders
23
- const lastHandlerRef = useRef(handler);
24
- useEffect(() => {
25
- lastHandlerRef.current = handler;
26
- }, [handler]);
27
-
22
+ const stableHandler = useDynamicCallback(handler);
28
23
  useEffect(
29
- () =>
30
- // See https://github.com/remix-run/history/blob/main/docs/blocking-transitions.md
31
- block((location, action) => lastHandlerRef.current(location, action)),
32
- [block, lastHandlerRef],
24
+ // See https://github.com/remix-run/history/blob/main/docs/blocking-transitions.md
25
+ () => block((location, action) => stableHandler(location, action)),
26
+ [block, stableHandler],
33
27
  );
34
28
  }
35
29
 
36
30
  /**
37
31
  * Permits to register a handler that will be called on history pop navigation
38
- * (backward/forward) If the handler returns false, the backward/forward
32
+ * (backward/forward). If the handler returns `false`, the backward/forward
39
33
  * transition will be blocked. Unfortunately there's no good way to detect the
40
34
  * "direction" (backward/forward) of the POP event.
41
35
  */
42
36
  export function useHistoryPopHandler(handler: HistoryBlockHandler): void {
43
37
  useHistoryActionHandler((location, action) => {
44
38
  if (action === 'POP') {
45
- // Eventually block navigation if handler returns false
39
+ // Maybe block navigation if handler returns false
46
40
  return handler(location, action);
47
41
  }
48
42
  // Don't block other navigation actions
@@ -26,7 +26,7 @@ export function duplicates<T>(
26
26
  }
27
27
 
28
28
  /**
29
- * Remove duplicate array items (similar to _.uniq)
29
+ * Remove duplicate array items (similar to `_.uniq`)
30
30
  * @param arr The array.
31
31
  * @returns An array with duplicate elements removed by reference comparison.
32
32
  */
@@ -0,0 +1,115 @@
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, {type ReactNode} from 'react';
9
+ import Head from '@docusaurus/Head';
10
+ import clsx from 'clsx';
11
+ import useRouteContext from '@docusaurus/useRouteContext';
12
+ import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
13
+ import {useTitleFormatter} from './generalUtils';
14
+
15
+ interface PageMetadataProps {
16
+ readonly title?: string;
17
+ readonly description?: string;
18
+ readonly keywords?: readonly string[] | string;
19
+ readonly image?: string;
20
+ readonly children?: ReactNode;
21
+ }
22
+
23
+ /**
24
+ * Helper component to manipulate page metadata and override site defaults.
25
+ * Works in the same way as Helmet.
26
+ */
27
+ export function PageMetadata({
28
+ title,
29
+ description,
30
+ keywords,
31
+ image,
32
+ children,
33
+ }: PageMetadataProps): JSX.Element {
34
+ const pageTitle = useTitleFormatter(title);
35
+ const {withBaseUrl} = useBaseUrlUtils();
36
+ const pageImage = image ? withBaseUrl(image, {absolute: true}) : undefined;
37
+
38
+ return (
39
+ <Head>
40
+ {title && <title>{pageTitle}</title>}
41
+ {title && <meta property="og:title" content={pageTitle} />}
42
+
43
+ {description && <meta name="description" content={description} />}
44
+ {description && <meta property="og:description" content={description} />}
45
+
46
+ {keywords && (
47
+ <meta
48
+ name="keywords"
49
+ content={
50
+ // https://github.com/microsoft/TypeScript/issues/17002
51
+ (Array.isArray(keywords) ? keywords.join(',') : keywords) as string
52
+ }
53
+ />
54
+ )}
55
+
56
+ {pageImage && <meta property="og:image" content={pageImage} />}
57
+ {pageImage && <meta name="twitter:image" content={pageImage} />}
58
+
59
+ {children}
60
+ </Head>
61
+ );
62
+ }
63
+
64
+ const HtmlClassNameContext = React.createContext<string | undefined>(undefined);
65
+
66
+ /**
67
+ * Every layer of this provider will append a class name to the HTML element.
68
+ * There's no consumer for this hook: it's side-effect-only. This wrapper is
69
+ * necessary because Helmet does not "merge" classes.
70
+ * @see https://github.com/staylor/react-helmet-async/issues/161
71
+ */
72
+ export function HtmlClassNameProvider({
73
+ className: classNameProp,
74
+ children,
75
+ }: {
76
+ className: string;
77
+ children: ReactNode;
78
+ }): JSX.Element {
79
+ const classNameContext = React.useContext(HtmlClassNameContext);
80
+ const className = clsx(classNameContext, classNameProp);
81
+ return (
82
+ <HtmlClassNameContext.Provider value={className}>
83
+ <Head>
84
+ <html className={className} />
85
+ </Head>
86
+ {children}
87
+ </HtmlClassNameContext.Provider>
88
+ );
89
+ }
90
+
91
+ function pluginNameToClassName(pluginName: string) {
92
+ return `plugin-${pluginName.replace(
93
+ /docusaurus-(?:plugin|theme)-(?:content-)?/gi,
94
+ '',
95
+ )}`;
96
+ }
97
+
98
+ /**
99
+ * A very thin wrapper around `HtmlClassNameProvider` that adds the plugin ID +
100
+ * name to the HTML class name.
101
+ */
102
+ export function PluginHtmlClassNameProvider({
103
+ children,
104
+ }: {
105
+ children: ReactNode;
106
+ }): JSX.Element {
107
+ const routeContext = useRouteContext();
108
+ const nameClass = pluginNameToClassName(routeContext.plugin.name);
109
+ const idClass = `plugin-id-${routeContext.plugin.id}`;
110
+ return (
111
+ <HtmlClassNameProvider className={clsx(nameClass, idClass)}>
112
+ {children}
113
+ </HtmlClassNameProvider>
114
+ );
115
+ }
@@ -0,0 +1,40 @@
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, {type ReactNode} from 'react';
9
+ import {NavbarMobileSidebarProvider} from '../contexts/navbarMobileSidebar';
10
+ import {NavbarSecondaryMenuProvider} from '../contexts/navbarSecondaryMenu';
11
+
12
+ const DefaultNavItemPosition = 'right';
13
+
14
+ /**
15
+ * Split links by left/right. If position is unspecified, fallback to right.
16
+ */
17
+ export function splitNavbarItems<T extends {position?: 'left' | 'right'}>(
18
+ items: T[],
19
+ ): [leftItems: T[], rightItems: T[]] {
20
+ function isLeft(item: T): boolean {
21
+ return (item.position ?? DefaultNavItemPosition) === 'left';
22
+ }
23
+
24
+ const leftItems = items.filter(isLeft);
25
+ const rightItems = items.filter((item) => !isLeft(item));
26
+
27
+ return [leftItems, rightItems];
28
+ }
29
+
30
+ /**
31
+ * Composes the `NavbarMobileSidebarProvider` and `NavbarSecondaryMenuProvider`.
32
+ * Because the latter depends on the former, they can't be re-ordered.
33
+ */
34
+ export function NavbarProvider({children}: {children: ReactNode}): JSX.Element {
35
+ return (
36
+ <NavbarMobileSidebarProvider>
37
+ <NavbarSecondaryMenuProvider>{children}</NavbarSecondaryMenuProvider>
38
+ </NavbarMobileSidebarProvider>
39
+ );
40
+ }
@@ -6,25 +6,29 @@
6
6
  */
7
7
 
8
8
  import {useCallback, useEffect, useLayoutEffect, useRef} from 'react';
9
+ import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
9
10
 
10
11
  /**
11
- * This hook is like useLayoutEffect, but without the SSR warning
12
- * It seems hacky but it's used in many React libs (Redux, Formik...)
12
+ * This hook is like `useLayoutEffect`, but without the SSR warning.
13
+ * It seems hacky but it's used in many React libs (Redux, Formik...).
13
14
  * Also mentioned here: https://github.com/facebook/react/issues/16956
15
+ *
14
16
  * It is useful when you need to update a ref as soon as possible after a React
15
- * render (before `useEffect`)
17
+ * render (before `useEffect`).
16
18
  */
17
- export const useIsomorphicLayoutEffect =
18
- typeof window !== 'undefined' ? useLayoutEffect : useEffect;
19
+ export const useIsomorphicLayoutEffect = ExecutionEnvironment.canUseDOM
20
+ ? useLayoutEffect
21
+ : useEffect;
19
22
 
20
23
  /**
21
24
  * Permits to transform an unstable callback (like an arrow function provided as
22
- * props) to a "stable" callback that is safe to use in a useEffect dependency
25
+ * props) to a "stable" callback that is safe to use in a `useEffect` dependency
23
26
  * array. Useful to avoid React stale closure problems + avoid useless effect
24
- * re-executions
27
+ * re-executions.
25
28
  *
26
29
  * Workaround until the React team recommends a good solution, see
27
30
  * https://github.com/facebook/react/issues/16956
31
+ *
28
32
  * This generally works but has some potential drawbacks, such as
29
33
  * https://github.com/facebook/react/issues/16956#issuecomment-536636418
30
34
  */
@@ -42,12 +46,31 @@ export function useDynamicCallback<T extends (...args: never[]) => unknown>(
42
46
  return useCallback<T>((...args) => ref.current(...args), []);
43
47
  }
44
48
 
49
+ /**
50
+ * Gets `value` from the last render.
51
+ */
52
+ export function usePrevious<T>(value: T): T | undefined {
53
+ const ref = useRef<T>();
54
+
55
+ useIsomorphicLayoutEffect(() => {
56
+ ref.current = value;
57
+ });
58
+
59
+ return ref.current;
60
+ }
61
+
62
+ /**
63
+ * This error is thrown when a context is consumed outside its provider. Allows
64
+ * reusing a generic error message format and reduces bundle size. The hook's
65
+ * name will be extracted from its stack, so only the provider's name is needed.
66
+ */
45
67
  export class ReactContextError extends Error {
46
68
  constructor(providerName: string, additionalInfo?: string) {
47
69
  super();
48
70
  this.name = 'ReactContextError';
49
71
  this.message = `Hook ${
50
- this.stack?.split('\n')[1]?.match(/at (?<name>\w+)/)?.groups!.name
72
+ this.stack?.split('\n')[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups!
73
+ .name
51
74
  } is called outside the <${providerName}>. ${additionalInfo || ''}`;
52
75
  }
53
76
  }
@@ -6,7 +6,8 @@
6
6
  */
7
7
 
8
8
  /**
9
- * Converts an optional string into a Regex case insensitive and global
9
+ * Matches a string regex (as provided from the config) against a target in a
10
+ * null-safe fashion, case insensitive and global.
10
11
  */
11
12
  export function isRegexpStringMatch(
12
13
  regexAsString?: string,
@@ -5,12 +5,31 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import GeneratedRoutes, {type Route} from '@generated/routes';
9
8
  import {useMemo} from 'react';
9
+ import generatedRoutes from '@generated/routes';
10
10
  import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
11
+ import type {Route} from '@docusaurus/types';
11
12
 
12
- // Note that all sites don't always have a homepage in practice
13
- // See https://github.com/facebook/docusaurus/pull/6517#issuecomment-1048709116
13
+ /**
14
+ * Compare the 2 paths, case insensitive and ignoring trailing slash
15
+ */
16
+ export function isSamePath(
17
+ path1: string | undefined,
18
+ path2: string | undefined,
19
+ ): boolean {
20
+ const normalize = (pathname: string | undefined) =>
21
+ (!pathname || pathname?.endsWith('/')
22
+ ? pathname
23
+ : `${pathname}/`
24
+ )?.toLowerCase();
25
+ return normalize(path1) === normalize(path2);
26
+ }
27
+
28
+ /**
29
+ * Note that sites don't always have a homepage in practice, so we can't assume
30
+ * that linking to '/' is always safe.
31
+ * @see https://github.com/facebook/docusaurus/pull/6517#issuecomment-1048709116
32
+ */
14
33
  export function findHomePageRoute({
15
34
  baseUrl,
16
35
  routes: initialRoutes,
@@ -43,14 +62,14 @@ export function findHomePageRoute({
43
62
  return doFindHomePageRoute(initialRoutes);
44
63
  }
45
64
 
65
+ /**
66
+ * Fetches the route that points to "/". Use this instead of the naive "/",
67
+ * because the homepage may not exist.
68
+ */
46
69
  export function useHomePageRoute(): Route | undefined {
47
70
  const {baseUrl} = useDocusaurusContext().siteConfig;
48
71
  return useMemo(
49
- () =>
50
- findHomePageRoute({
51
- routes: GeneratedRoutes,
52
- baseUrl,
53
- }),
72
+ () => findHomePageRoute({routes: generatedRoutes, baseUrl}),
54
73
  [baseUrl],
55
74
  );
56
75
  }