@docusaurus/theme-common 2.0.0-beta.fc64c12e4 → 2.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.
Files changed (274) hide show
  1. package/lib/components/Collapsible/index.d.ts +35 -6
  2. package/lib/components/Collapsible/index.d.ts.map +1 -0
  3. package/lib/components/Collapsible/index.js +33 -30
  4. package/lib/components/Collapsible/index.js.map +1 -0
  5. package/lib/components/Details/index.d.ts +8 -3
  6. package/lib/components/Details/index.d.ts.map +1 -0
  7. package/lib/components/Details/index.js +31 -19
  8. package/lib/components/Details/index.js.map +1 -0
  9. package/lib/components/Details/styles.module.css +14 -11
  10. package/lib/contexts/announcementBar.d.ts +22 -0
  11. package/lib/contexts/announcementBar.d.ts.map +1 -0
  12. package/lib/{utils/announcementBarUtils.js → contexts/announcementBar.js} +30 -31
  13. package/lib/contexts/announcementBar.js.map +1 -0
  14. package/lib/contexts/blogPost.d.ts +33 -0
  15. package/lib/contexts/blogPost.d.ts.map +1 -0
  16. package/lib/contexts/blogPost.js +46 -0
  17. package/lib/contexts/blogPost.js.map +1 -0
  18. package/lib/contexts/colorMode.d.ts +27 -0
  19. package/lib/contexts/colorMode.d.ts.map +1 -0
  20. package/lib/contexts/colorMode.js +132 -0
  21. package/lib/contexts/colorMode.js.map +1 -0
  22. package/lib/contexts/doc.d.ts +30 -0
  23. package/lib/contexts/doc.d.ts.map +1 -0
  24. package/lib/contexts/doc.js +48 -0
  25. package/lib/contexts/doc.js.map +1 -0
  26. package/lib/contexts/docSidebarItemsExpandedState.d.ts +31 -0
  27. package/lib/contexts/docSidebarItemsExpandedState.d.ts.map +1 -0
  28. package/lib/contexts/docSidebarItemsExpandedState.js +28 -0
  29. package/lib/contexts/docSidebarItemsExpandedState.js.map +1 -0
  30. package/lib/contexts/docsPreferredVersion.d.ts +30 -0
  31. package/lib/contexts/docsPreferredVersion.d.ts.map +1 -0
  32. package/lib/contexts/docsPreferredVersion.js +130 -0
  33. package/lib/contexts/docsPreferredVersion.js.map +1 -0
  34. package/lib/contexts/docsSidebar.d.ts +26 -0
  35. package/lib/contexts/docsSidebar.d.ts.map +1 -0
  36. package/lib/contexts/docsSidebar.js +30 -0
  37. package/lib/contexts/docsSidebar.js.map +1 -0
  38. package/lib/contexts/docsVersion.d.ts +20 -0
  39. package/lib/contexts/docsVersion.d.ts.map +1 -0
  40. package/lib/contexts/docsVersion.js +26 -0
  41. package/lib/contexts/docsVersion.js.map +1 -0
  42. package/lib/contexts/navbarMobileSidebar.d.ts +31 -0
  43. package/lib/contexts/navbarMobileSidebar.d.ts.map +1 -0
  44. package/lib/contexts/navbarMobileSidebar.js +56 -0
  45. package/lib/contexts/navbarMobileSidebar.js.map +1 -0
  46. package/lib/contexts/navbarSecondaryMenu/content.d.ts +37 -0
  47. package/lib/contexts/navbarSecondaryMenu/content.d.ts.map +1 -0
  48. package/lib/contexts/navbarSecondaryMenu/content.js +50 -0
  49. package/lib/contexts/navbarSecondaryMenu/content.js.map +1 -0
  50. package/lib/contexts/navbarSecondaryMenu/display.d.ts +24 -0
  51. package/lib/contexts/navbarSecondaryMenu/display.d.ts.map +1 -0
  52. package/lib/contexts/navbarSecondaryMenu/display.js +62 -0
  53. package/lib/contexts/navbarSecondaryMenu/display.js.map +1 -0
  54. package/lib/contexts/tabGroupChoice.d.ts +21 -0
  55. package/lib/contexts/tabGroupChoice.d.ts.map +1 -0
  56. package/lib/contexts/tabGroupChoice.js +49 -0
  57. package/lib/contexts/tabGroupChoice.js.map +1 -0
  58. package/lib/{utils/usePrevious.d.ts → hooks/styles.css} +4 -1
  59. package/lib/hooks/useBackToTopButton.d.ts +27 -0
  60. package/lib/hooks/useBackToTopButton.d.ts.map +1 -0
  61. package/lib/hooks/useBackToTopButton.js +50 -0
  62. package/lib/hooks/useBackToTopButton.js.map +1 -0
  63. package/lib/hooks/useCodeWordWrap.d.ts +14 -0
  64. package/lib/hooks/useCodeWordWrap.d.ts.map +1 -0
  65. package/lib/hooks/useCodeWordWrap.js +67 -0
  66. package/lib/hooks/useCodeWordWrap.js.map +1 -0
  67. package/lib/hooks/useHideableNavbar.d.ts +17 -0
  68. package/lib/hooks/useHideableNavbar.d.ts.map +1 -0
  69. package/lib/hooks/useHideableNavbar.js +60 -0
  70. package/lib/hooks/useHideableNavbar.js.map +1 -0
  71. package/lib/hooks/useKeyboardNavigation.d.ts +20 -0
  72. package/lib/hooks/useKeyboardNavigation.d.ts.map +1 -0
  73. package/lib/hooks/useKeyboardNavigation.js +39 -0
  74. package/lib/hooks/useKeyboardNavigation.js.map +1 -0
  75. package/lib/hooks/useLockBodyScroll.d.ts +12 -0
  76. package/lib/hooks/useLockBodyScroll.d.ts.map +1 -0
  77. package/lib/hooks/useLockBodyScroll.js +20 -0
  78. package/lib/hooks/useLockBodyScroll.js.map +1 -0
  79. package/lib/hooks/useMutationObserver.d.ts +4 -0
  80. package/lib/hooks/useMutationObserver.d.ts.map +1 -0
  81. package/lib/hooks/useMutationObserver.js +29 -0
  82. package/lib/hooks/useMutationObserver.js.map +1 -0
  83. package/lib/hooks/usePrismTheme.d.ts +13 -0
  84. package/lib/hooks/usePrismTheme.d.ts.map +1 -0
  85. package/lib/hooks/usePrismTheme.js +21 -0
  86. package/lib/hooks/usePrismTheme.js.map +1 -0
  87. package/lib/hooks/useSearchPage.d.ts +25 -0
  88. package/lib/hooks/useSearchPage.d.ts.map +1 -0
  89. package/lib/hooks/useSearchPage.js +43 -0
  90. package/lib/hooks/useSearchPage.js.map +1 -0
  91. package/lib/hooks/useSkipToContent.d.ts +25 -0
  92. package/lib/hooks/useSkipToContent.d.ts.map +1 -0
  93. package/lib/hooks/useSkipToContent.js +35 -0
  94. package/lib/hooks/useSkipToContent.js.map +1 -0
  95. package/lib/hooks/useTOCHighlight.d.ts +25 -0
  96. package/lib/hooks/useTOCHighlight.d.ts.map +1 -0
  97. package/lib/hooks/useTOCHighlight.js +130 -0
  98. package/lib/hooks/useTOCHighlight.js.map +1 -0
  99. package/lib/hooks/useWindowSize.d.ts +28 -0
  100. package/lib/hooks/useWindowSize.d.ts.map +1 -0
  101. package/lib/hooks/useWindowSize.js +59 -0
  102. package/lib/hooks/useWindowSize.js.map +1 -0
  103. package/lib/index.d.ts +15 -19
  104. package/lib/index.d.ts.map +1 -0
  105. package/lib/index.js +22 -15
  106. package/lib/index.js.map +1 -0
  107. package/lib/internal.d.ts +41 -0
  108. package/lib/internal.d.ts.map +1 -0
  109. package/lib/internal.js +52 -0
  110. package/lib/internal.js.map +1 -0
  111. package/lib/utils/ThemeClassNames.d.ts +49 -12
  112. package/lib/utils/ThemeClassNames.d.ts.map +1 -0
  113. package/lib/utils/ThemeClassNames.js +47 -4
  114. package/lib/utils/ThemeClassNames.js.map +1 -0
  115. package/lib/utils/codeBlockUtils.d.ts +63 -0
  116. package/lib/utils/codeBlockUtils.d.ts.map +1 -0
  117. package/lib/utils/codeBlockUtils.js +159 -3
  118. package/lib/utils/codeBlockUtils.js.map +1 -0
  119. package/lib/utils/docsUtils.d.ts +91 -0
  120. package/lib/utils/docsUtils.d.ts.map +1 -0
  121. package/lib/utils/docsUtils.js +217 -1
  122. package/lib/utils/docsUtils.js.map +1 -0
  123. package/lib/utils/footerUtils.d.ts +13 -0
  124. package/lib/utils/footerUtils.d.ts.map +1 -0
  125. package/lib/utils/footerUtils.js +14 -0
  126. package/lib/utils/footerUtils.js.map +1 -0
  127. package/lib/utils/generalUtils.d.ts +11 -1
  128. package/lib/utils/generalUtils.d.ts.map +1 -0
  129. package/lib/utils/generalUtils.js +9 -5
  130. package/lib/utils/generalUtils.js.map +1 -0
  131. package/lib/utils/historyUtils.d.ts +17 -0
  132. package/lib/utils/historyUtils.d.ts.map +1 -0
  133. package/lib/utils/historyUtils.js +38 -0
  134. package/lib/utils/historyUtils.js.map +1 -0
  135. package/lib/utils/jsUtils.d.ts +23 -0
  136. package/lib/utils/jsUtils.d.ts.map +1 -0
  137. package/lib/utils/jsUtils.js +29 -0
  138. package/lib/utils/jsUtils.js.map +1 -0
  139. package/lib/utils/metadataUtils.d.ts +38 -0
  140. package/lib/utils/metadataUtils.d.ts.map +1 -0
  141. package/lib/utils/metadataUtils.js +70 -0
  142. package/lib/utils/metadataUtils.js.map +1 -0
  143. package/lib/utils/navbarUtils.d.ts +21 -0
  144. package/lib/utils/navbarUtils.d.ts.map +1 -0
  145. package/lib/utils/navbarUtils.js +36 -0
  146. package/lib/utils/navbarUtils.js.map +1 -0
  147. package/lib/utils/reactUtils.d.ts +69 -0
  148. package/lib/utils/reactUtils.d.ts.map +1 -0
  149. package/lib/utils/reactUtils.js +98 -0
  150. package/lib/utils/reactUtils.js.map +1 -0
  151. package/lib/utils/regexpUtils.d.ts +12 -0
  152. package/lib/utils/regexpUtils.d.ts.map +1 -0
  153. package/lib/utils/regexpUtils.js +18 -0
  154. package/lib/utils/regexpUtils.js.map +1 -0
  155. package/lib/utils/routesUtils.d.ts +26 -0
  156. package/lib/utils/routesUtils.d.ts.map +1 -0
  157. package/lib/utils/routesUtils.js +54 -0
  158. package/lib/utils/routesUtils.js.map +1 -0
  159. package/lib/utils/scrollUtils.d.ts +83 -0
  160. package/lib/utils/scrollUtils.d.ts.map +1 -0
  161. package/lib/utils/scrollUtils.js +200 -0
  162. package/lib/utils/scrollUtils.js.map +1 -0
  163. package/lib/utils/searchUtils.d.ts +13 -0
  164. package/lib/utils/searchUtils.d.ts.map +1 -0
  165. package/lib/utils/searchUtils.js +37 -0
  166. package/lib/utils/searchUtils.js.map +1 -0
  167. package/lib/utils/storageUtils.d.ts +15 -7
  168. package/lib/utils/storageUtils.d.ts.map +1 -0
  169. package/lib/utils/storageUtils.js +55 -22
  170. package/lib/utils/storageUtils.js.map +1 -0
  171. package/lib/utils/tagsUtils.d.ts +18 -0
  172. package/lib/utils/tagsUtils.d.ts.map +1 -0
  173. package/lib/utils/tagsUtils.js +36 -0
  174. package/lib/utils/tagsUtils.js.map +1 -0
  175. package/lib/utils/tocUtils.d.ts +36 -0
  176. package/lib/utils/tocUtils.d.ts.map +1 -0
  177. package/lib/utils/tocUtils.js +84 -0
  178. package/lib/utils/tocUtils.js.map +1 -0
  179. package/lib/utils/useAlternatePageUtils.d.ts +21 -1
  180. package/lib/utils/useAlternatePageUtils.d.ts.map +1 -0
  181. package/lib/utils/useAlternatePageUtils.js +9 -4
  182. package/lib/utils/useAlternatePageUtils.js.map +1 -0
  183. package/lib/utils/useLocalPathname.d.ts +6 -0
  184. package/lib/utils/useLocalPathname.d.ts.map +1 -0
  185. package/lib/utils/useLocalPathname.js +7 -4
  186. package/lib/utils/useLocalPathname.js.map +1 -0
  187. package/lib/utils/useLocationChange.d.ts +9 -6
  188. package/lib/utils/useLocationChange.d.ts.map +1 -0
  189. package/lib/utils/useLocationChange.js +17 -11
  190. package/lib/utils/useLocationChange.js.map +1 -0
  191. package/lib/utils/usePluralForm.d.ts +12 -0
  192. package/lib/utils/usePluralForm.d.ts.map +1 -0
  193. package/lib/utils/usePluralForm.js +36 -37
  194. package/lib/utils/usePluralForm.js.map +1 -0
  195. package/lib/utils/useThemeConfig.d.ts +56 -29
  196. package/lib/utils/useThemeConfig.d.ts.map +1 -0
  197. package/lib/utils/useThemeConfig.js +4 -0
  198. package/lib/utils/useThemeConfig.js.map +1 -0
  199. package/package.json +35 -15
  200. package/src/components/Collapsible/index.tsx +57 -48
  201. package/src/components/Details/index.tsx +27 -12
  202. package/src/components/Details/styles.module.css +14 -11
  203. package/src/{utils/announcementBarUtils.tsx → contexts/announcementBar.tsx} +43 -39
  204. package/src/contexts/blogPost.tsx +80 -0
  205. package/src/contexts/colorMode.tsx +198 -0
  206. package/src/contexts/doc.tsx +71 -0
  207. package/src/contexts/docSidebarItemsExpandedState.tsx +55 -0
  208. package/src/contexts/docsPreferredVersion.tsx +251 -0
  209. package/src/contexts/docsSidebar.tsx +50 -0
  210. package/src/contexts/docsVersion.tsx +36 -0
  211. package/src/contexts/navbarMobileSidebar.tsx +99 -0
  212. package/src/contexts/navbarSecondaryMenu/content.tsx +100 -0
  213. package/src/contexts/navbarSecondaryMenu/display.tsx +102 -0
  214. package/src/contexts/tabGroupChoice.tsx +85 -0
  215. package/{lib/utils/pathUtils.d.ts → src/hooks/styles.css} +4 -1
  216. package/src/hooks/useBackToTopButton.ts +73 -0
  217. package/src/hooks/useCodeWordWrap.ts +105 -0
  218. package/src/hooks/useHideableNavbar.ts +75 -0
  219. package/src/hooks/useKeyboardNavigation.ts +45 -0
  220. package/src/hooks/useLockBodyScroll.ts +21 -0
  221. package/src/hooks/useMutationObserver.ts +38 -0
  222. package/src/hooks/usePrismTheme.ts +24 -0
  223. package/src/hooks/useSearchPage.ts +79 -0
  224. package/src/hooks/useSkipToContent.ts +58 -0
  225. package/src/hooks/useTOCHighlight.ts +189 -0
  226. package/src/hooks/useWindowSize.ts +72 -0
  227. package/src/index.ts +49 -42
  228. package/src/internal.ts +122 -0
  229. package/src/types.d.ts +0 -2
  230. package/src/utils/ThemeClassNames.ts +54 -5
  231. package/src/utils/codeBlockUtils.ts +241 -2
  232. package/src/utils/docsUtils.tsx +334 -0
  233. package/src/utils/footerUtils.ts +18 -0
  234. package/src/utils/generalUtils.ts +9 -5
  235. package/src/utils/historyUtils.ts +45 -0
  236. package/src/utils/jsUtils.ts +36 -0
  237. package/src/utils/metadataUtils.tsx +115 -0
  238. package/src/utils/navbarUtils.tsx +45 -0
  239. package/src/utils/reactUtils.tsx +129 -0
  240. package/src/utils/regexpUtils.ts +24 -0
  241. package/src/utils/routesUtils.ts +75 -0
  242. package/src/utils/scrollUtils.tsx +304 -0
  243. package/src/utils/searchUtils.ts +51 -0
  244. package/src/utils/storageUtils.ts +56 -23
  245. package/src/utils/tagsUtils.ts +50 -0
  246. package/src/utils/tocUtils.ts +119 -0
  247. package/src/utils/useAlternatePageUtils.ts +19 -6
  248. package/src/utils/useLocalPathname.ts +6 -4
  249. package/src/utils/useLocationChange.ts +24 -20
  250. package/src/utils/usePluralForm.ts +50 -38
  251. package/src/utils/useThemeConfig.ts +55 -31
  252. package/copyUntypedFiles.js +0 -20
  253. package/lib/.tsbuildinfo +0 -1
  254. package/lib/utils/announcementBarUtils.d.ts +0 -17
  255. package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.d.ts +0 -21
  256. package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.js +0 -94
  257. package/lib/utils/docsPreferredVersion/DocsPreferredVersionStorage.d.ts +0 -13
  258. package/lib/utils/docsPreferredVersion/DocsPreferredVersionStorage.js +0 -20
  259. package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.d.ts +0 -5
  260. package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.js +0 -41
  261. package/lib/utils/mobileSecondaryMenu.d.ts +0 -20
  262. package/lib/utils/mobileSecondaryMenu.js +0 -50
  263. package/lib/utils/pathUtils.js +0 -13
  264. package/lib/utils/usePrevious.js +0 -14
  265. package/src/utils/__tests__/codeBlockUtils.test.ts +0 -54
  266. package/src/utils/__tests__/pathUtils.test.ts +0 -32
  267. package/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx +0 -165
  268. package/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts +0 -34
  269. package/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts +0 -66
  270. package/src/utils/docsUtils.ts +0 -11
  271. package/src/utils/mobileSecondaryMenu.tsx +0 -115
  272. package/src/utils/pathUtils.ts +0 -17
  273. package/src/utils/usePrevious.ts +0 -18
  274. package/tsconfig.json +0 -10
@@ -5,35 +5,34 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
9
8
  import React, {
10
9
  useState,
11
10
  useEffect,
12
11
  useRef,
13
12
  useCallback,
14
- RefObject,
15
- Dispatch,
16
- SetStateAction,
17
- ReactNode,
18
13
  useLayoutEffect,
14
+ type RefObject,
15
+ type Dispatch,
16
+ type SetStateAction,
17
+ type ReactNode,
19
18
  } from 'react';
19
+ import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
20
20
 
21
21
  const DefaultAnimationEasing = 'ease-in-out';
22
22
 
23
- export type UseCollapsibleConfig = {
24
- initialState: boolean | (() => boolean);
25
- };
26
-
27
- export type UseCollapsibleReturns = {
23
+ /**
24
+ * This hook is a very thin wrapper around a `useState`.
25
+ */
26
+ export function useCollapsible({
27
+ initialState,
28
+ }: {
29
+ /** The initial state. Will be non-collapsed by default. */
30
+ initialState?: boolean | (() => boolean);
31
+ }): {
28
32
  collapsed: boolean;
29
33
  setCollapsed: Dispatch<SetStateAction<boolean>>;
30
34
  toggleCollapsed: () => void;
31
- };
32
-
33
- // This hook just define the state
34
- export function useCollapsible({
35
- initialState,
36
- }: UseCollapsibleConfig): UseCollapsibleReturns {
35
+ } {
37
36
  const [collapsed, setCollapsed] = useState(initialState ?? false);
38
37
 
39
38
  const toggleCollapsed = useCallback(() => {
@@ -67,7 +66,8 @@ function applyCollapsedStyle(el: HTMLElement, collapsed: boolean) {
67
66
  }
68
67
 
69
68
  /*
70
- Lex111: Dynamic transition duration is used in Material design, this technique is good for a large number of items.
69
+ Lex111: Dynamic transition duration is used in Material design, this technique
70
+ is good for a large number of items.
71
71
  https://material.io/archive/guidelines/motion/duration-easing.html#duration-easing-dynamic-durations
72
72
  https://github.com/mui-org/material-ui/blob/e724d98eba018e55e1a684236a2037e24bcf050c/packages/material-ui/src/styles/createTransitions.js#L40-L43
73
73
  */
@@ -120,7 +120,7 @@ function useCollapseAnimation({
120
120
 
121
121
  el.style.willChange = 'height';
122
122
 
123
- function startAnimation(): () => void {
123
+ function startAnimation() {
124
124
  const animationFrame = requestAnimationFrame(() => {
125
125
  // When collapsing
126
126
  if (collapsed) {
@@ -151,7 +151,10 @@ type CollapsibleElementType = React.ElementType<
151
151
  Pick<React.HTMLAttributes<unknown>, 'className' | 'onTransitionEnd' | 'style'>
152
152
  >;
153
153
 
154
- // Prevent hydration layout shift before anims are handled imperatively with JS
154
+ /**
155
+ * Prevent hydration layout shift before animations are handled imperatively
156
+ * with JS
157
+ */
155
158
  function getSSRStyle(collapsed: boolean) {
156
159
  if (ExecutionEnvironment.canUseDOM) {
157
160
  return undefined;
@@ -160,15 +163,27 @@ function getSSRStyle(collapsed: boolean) {
160
163
  }
161
164
 
162
165
  type CollapsibleBaseProps = {
166
+ /** The actual DOM element to be used in the markup. */
163
167
  as?: CollapsibleElementType;
168
+ /** Initial collapsed state. */
164
169
  collapsed: boolean;
165
170
  children: ReactNode;
171
+ /** Configuration of animation, like `duration` and `easing` */
166
172
  animation?: CollapsibleAnimationConfig;
173
+ /**
174
+ * A callback fired when the collapse transition animation ends. Receives
175
+ * the **new** collapsed state: e.g. when
176
+ * expanding, `collapsed` will be `false`. You can use this for some "cleanup"
177
+ * like applying new styles when the container is fully expanded.
178
+ */
167
179
  onCollapseTransitionEnd?: (collapsed: boolean) => void;
180
+ /** Class name for the underlying DOM element. */
168
181
  className?: string;
169
-
170
- // This is mostly useful for details/summary component where ssrStyle is not needed (as details are hidden natively)
171
- // and can mess-up with the default native behavior of the browser when JS fails to load or is disabled
182
+ /**
183
+ * This is mostly useful for details/summary component where ssrStyle is not
184
+ * needed (as details are hidden natively) and can mess up with the browser's
185
+ * native behavior when JS fails to load or is disabled
186
+ */
172
187
  disableSSRStyle?: boolean;
173
188
  };
174
189
 
@@ -181,36 +196,23 @@ function CollapsibleBase({
181
196
  className,
182
197
  disableSSRStyle,
183
198
  }: CollapsibleBaseProps) {
184
- // any because TS is a pain for HTML element refs, see https://twitter.com/sebastienlorber/status/1412784677795110914
185
- const collapsibleRef = useRef<any>(null);
199
+ const collapsibleRef = useRef<HTMLElement>(null);
186
200
 
187
201
  useCollapseAnimation({collapsibleRef, collapsed, animation});
188
202
 
189
203
  return (
190
204
  <As
191
- // @ts-expect-error: see https://twitter.com/sebastienlorber/status/1412784677795110914
192
- ref={collapsibleRef}
205
+ // @ts-expect-error: the "too complicated type" is produced from
206
+ // "CollapsibleElementType" being a huge union
207
+ ref={collapsibleRef as RefObject<never>} // Refs are contravariant, which is not expressible in TS
193
208
  style={disableSSRStyle ? undefined : getSSRStyle(collapsed)}
194
- onTransitionEnd={(e) => {
209
+ onTransitionEnd={(e: React.TransitionEvent) => {
195
210
  if (e.propertyName !== 'height') {
196
211
  return;
197
212
  }
198
213
 
199
- const el = collapsibleRef.current!;
200
- const currentCollapsibleElementHeight = el.style.height;
201
-
202
- if (
203
- !collapsed &&
204
- parseInt(currentCollapsibleElementHeight, 10) === el.scrollHeight
205
- ) {
206
- applyCollapsedStyle(el, false);
207
- onCollapseTransitionEnd?.(false);
208
- }
209
-
210
- if (currentCollapsibleElementHeight === CollapsedStyles.height) {
211
- applyCollapsedStyle(el, true);
212
- onCollapseTransitionEnd?.(true);
213
- }
214
+ applyCollapsedStyle(collapsibleRef.current!, collapsed);
215
+ onCollapseTransitionEnd?.(collapsed);
214
216
  }}
215
217
  className={className}>
216
218
  {children}
@@ -220,6 +222,8 @@ function CollapsibleBase({
220
222
 
221
223
  function CollapsibleLazy({collapsed, ...props}: CollapsibleBaseProps) {
222
224
  const [mounted, setMounted] = useState(!collapsed);
225
+ // Updated in effect so that first expansion transition can work
226
+ const [lazyCollapsed, setLazyCollapsed] = useState(collapsed);
223
227
 
224
228
  useLayoutEffect(() => {
225
229
  if (!collapsed) {
@@ -227,8 +231,6 @@ function CollapsibleLazy({collapsed, ...props}: CollapsibleBaseProps) {
227
231
  }
228
232
  }, [collapsed]);
229
233
 
230
- // lazyCollapsed updated in effect so that the first expansion transition can work
231
- const [lazyCollapsed, setLazyCollapsed] = useState(collapsed);
232
234
  useLayoutEffect(() => {
233
235
  if (mounted) {
234
236
  setLazyCollapsed(collapsed);
@@ -241,13 +243,20 @@ function CollapsibleLazy({collapsed, ...props}: CollapsibleBaseProps) {
241
243
  }
242
244
 
243
245
  type CollapsibleProps = CollapsibleBaseProps & {
244
- // Lazy allows to delay the rendering when collapsed => it will render children only after hydration, on first expansion
245
- // Required prop: it forces to think if content should be server-rendered or not!
246
- // This has perf impact on the SSR output and html file sizes
247
- // See https://github.com/facebook/docusaurus/issues/4753
246
+ /**
247
+ * Delay rendering of the content till first expansion. Marked as required to
248
+ * force us to think if content should be server-rendered or not. This has
249
+ * perf impact since it reduces html file sizes, but could undermine SEO.
250
+ * @see https://github.com/facebook/docusaurus/issues/4753
251
+ */
248
252
  lazy: boolean;
249
253
  };
250
254
 
255
+ /**
256
+ * A headless component providing smooth and uniform collapsing behavior. The
257
+ * component will be invisible (zero height) when collapsed. Doesn't provide
258
+ * interactivity by itself: collapse state is toggled through props.
259
+ */
251
260
  export function Collapsible({lazy, ...props}: CollapsibleProps): JSX.Element {
252
261
  const Comp = lazy ? CollapsibleLazy : CollapsibleBase;
253
262
  return <Comp {...props} />;
@@ -5,9 +5,14 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import React, {ComponentProps, ReactElement, useRef, useState} from 'react';
9
- import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
8
+ import React, {
9
+ useRef,
10
+ useState,
11
+ type ComponentProps,
12
+ type ReactElement,
13
+ } from 'react';
10
14
  import clsx from 'clsx';
15
+ import useIsBrowser from '@docusaurus/useIsBrowser';
11
16
  import {useCollapsible, Collapsible} from '../Collapsible';
12
17
  import styles from './styles.module.css';
13
18
 
@@ -26,21 +31,31 @@ function hasParent(node: HTMLElement | null, parent: HTMLElement): boolean {
26
31
  }
27
32
 
28
33
  export type DetailsProps = {
34
+ /** Summary is provided as props, including the wrapping `<summary>` tag */
29
35
  summary?: ReactElement;
30
36
  } & ComponentProps<'details'>;
31
37
 
32
- const Details = ({summary, children, ...props}: DetailsProps): JSX.Element => {
33
- const {isClient} = useDocusaurusContext();
38
+ /**
39
+ * A mostly un-styled `<details>` element with smooth collapsing. Provides some
40
+ * very lightweight styles, but you should bring your UI.
41
+ */
42
+ export function Details({
43
+ summary,
44
+ children,
45
+ ...props
46
+ }: DetailsProps): JSX.Element {
47
+ const isBrowser = useIsBrowser();
34
48
  const detailsRef = useRef<HTMLDetailsElement>(null);
35
49
 
36
50
  const {collapsed, setCollapsed} = useCollapsible({
37
51
  initialState: !props.open,
38
52
  });
39
- // We use a separate prop because it must be set only after animation completes
40
- // Otherwise close anim won't work
53
+ // Use a separate state for the actual details prop, because it must be set
54
+ // only after animation completes, otherwise close animations won't work
41
55
  const [open, setOpen] = useState(props.open);
42
56
 
43
57
  return (
58
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
44
59
  <details
45
60
  {...props}
46
61
  ref={detailsRef}
@@ -48,7 +63,7 @@ const Details = ({summary, children, ...props}: DetailsProps): JSX.Element => {
48
63
  data-collapsed={collapsed}
49
64
  className={clsx(
50
65
  styles.details,
51
- {[styles.isClient]: isClient},
66
+ isBrowser && styles.isBrowser,
52
67
  props.className,
53
68
  )}
54
69
  onMouseDown={(e) => {
@@ -72,10 +87,12 @@ const Details = ({summary, children, ...props}: DetailsProps): JSX.Element => {
72
87
  setOpen(true);
73
88
  } else {
74
89
  setCollapsed(true);
75
- // setOpen(false); // Don't do this, it breaks close animation!
90
+ // Don't do this, it breaks close animation!
91
+ // setOpen(false);
76
92
  }
77
93
  }}>
78
- {summary}
94
+ {/* eslint-disable-next-line @docusaurus/no-untranslated-text */}
95
+ {summary ?? <summary>Details</summary>}
79
96
 
80
97
  <Collapsible
81
98
  lazy={false} // Content might matter for SEO in this case
@@ -89,6 +106,4 @@ const Details = ({summary, children, ...props}: DetailsProps): JSX.Element => {
89
106
  </Collapsible>
90
107
  </details>
91
108
  );
92
- };
93
-
94
- export default Details;
109
+ }
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  /*
9
- CSS variables, meant to be overriden by final theme
9
+ CSS variables, meant to be overridden by final theme
10
10
  */
11
11
  .details {
12
12
  --docusaurus-details-summary-arrow-size: 0.38rem;
@@ -18,25 +18,24 @@ CSS variables, meant to be overriden by final theme
18
18
  position: relative;
19
19
  cursor: pointer;
20
20
  list-style: none;
21
- margin-left: 1.8rem;
21
+ padding-left: 1rem;
22
22
  }
23
23
 
24
+ /* TODO: deprecation, need to remove this after Safari will support `::marker` */
24
25
  .details > summary::-webkit-details-marker {
25
26
  display: none;
26
27
  }
27
28
 
28
- .details > summary:before {
29
+ .details > summary::before {
29
30
  position: absolute;
30
31
  top: 0.45rem;
31
- left: -1.2rem;
32
+ left: 0;
32
33
 
33
34
  /* CSS-only Arrow */
34
35
  content: '';
35
- width: 0;
36
- height: 0;
37
- border-top: var(--docusaurus-details-summary-arrow-size) solid transparent;
38
- border-bottom: var(--docusaurus-details-summary-arrow-size) solid transparent;
39
- border-left: var(--docusaurus-details-summary-arrow-size) solid
36
+ border-width: var(--docusaurus-details-summary-arrow-size);
37
+ border-style: solid;
38
+ border-color: transparent transparent transparent
40
39
  var(--docusaurus-details-decoration-color);
41
40
 
42
41
  /* Arrow rotation anim */
@@ -46,9 +45,9 @@ CSS variables, meant to be overriden by final theme
46
45
  }
47
46
 
48
47
  /* When JS disabled/failed to load: we use the open property for arrow animation: */
49
- .details[open]:not(.isClient) > summary:before,
48
+ .details[open]:not(.isBrowser) > summary::before,
50
49
  /* When JS works: we use the data-attribute for arrow animation */
51
- .details[data-collapsed='false'].isClient > summary:before {
50
+ .details[data-collapsed='false'].isBrowser > summary::before {
52
51
  transform: rotate(90deg);
53
52
  }
54
53
 
@@ -57,3 +56,7 @@ CSS variables, meant to be overriden by final theme
57
56
  border-top: 1px solid var(--docusaurus-details-decoration-color);
58
57
  padding-top: 1rem;
59
58
  }
59
+
60
+ .collapsibleContent > *:last-child {
61
+ margin-bottom: 0;
62
+ }
@@ -10,13 +10,13 @@ import React, {
10
10
  useEffect,
11
11
  useCallback,
12
12
  useMemo,
13
- ReactNode,
14
13
  useContext,
15
- createContext,
14
+ type ReactNode,
16
15
  } from 'react';
17
- import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
18
- import {createStorageSlot} from './storageUtils';
19
- import {useThemeConfig} from './useThemeConfig';
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
20
 
21
21
  export const AnnouncementBarDismissStorageKey =
22
22
  'docusaurus.announcement.dismiss';
@@ -32,22 +32,28 @@ const isDismissedInStorage = () =>
32
32
  const setDismissedInStorage = (bool: boolean) =>
33
33
  AnnouncementBarDismissStorage.set(String(bool));
34
34
 
35
- type AnnouncementBarAPI = {
36
- readonly isClosed: boolean;
35
+ type ContextValue = {
36
+ /** Whether the announcement bar should be displayed. */
37
+ readonly isActive: boolean;
38
+ /**
39
+ * Callback fired when the user closes the announcement. Will be saved.
40
+ */
37
41
  readonly close: () => void;
38
42
  };
39
43
 
40
- const useAnnouncementBarContextValue = (): AnnouncementBarAPI => {
44
+ const Context = React.createContext<ContextValue | null>(null);
45
+
46
+ function useContextValue(): ContextValue {
41
47
  const {announcementBar} = useThemeConfig();
42
- const {isClient} = useDocusaurusContext();
48
+ const isBrowser = useIsBrowser();
43
49
 
44
- const [isClosed, setClosed] = useState(() => {
45
- return isClient
46
- ? // On client navigation: init with localstorage value
50
+ const [isClosed, setClosed] = useState(() =>
51
+ isBrowser
52
+ ? // On client navigation: init with local storage value
47
53
  isDismissedInStorage()
48
54
  : // On server/hydration: always visible to prevent layout shifts (will be hidden with css if needed)
49
- false;
50
- });
55
+ false,
56
+ );
51
57
  // Update state after hydration
52
58
  useEffect(() => {
53
59
  setClosed(isDismissedInStorage());
@@ -66,8 +72,9 @@ const useAnnouncementBarContextValue = (): AnnouncementBarAPI => {
66
72
 
67
73
  let viewedId = IdStorage.get();
68
74
 
69
- // retrocompatibility due to spelling mistake of default id
75
+ // Retrocompatibility due to spelling mistake of default id
70
76
  // see https://github.com/facebook/docusaurus/issues/3338
77
+ // cSpell:ignore annoucement
71
78
  if (viewedId === 'annoucement-bar') {
72
79
  viewedId = 'announcement-bar';
73
80
  }
@@ -83,33 +90,30 @@ const useAnnouncementBarContextValue = (): AnnouncementBarAPI => {
83
90
  if (isNewAnnouncement || !isDismissedInStorage()) {
84
91
  setClosed(false);
85
92
  }
86
- }, []);
93
+ }, [announcementBar]);
87
94
 
88
- return useMemo(() => {
89
- return {
90
- isClosed,
95
+ return useMemo(
96
+ () => ({
97
+ isActive: !!announcementBar && !isClosed,
91
98
  close: handleClose,
92
- };
93
- }, [isClosed]);
94
- };
95
-
96
- const AnnouncementBarContext = createContext<AnnouncementBarAPI | null>(null);
97
-
98
- export const AnnouncementBarProvider = ({children}: {children: ReactNode}) => {
99
- const value = useAnnouncementBarContextValue();
100
- return (
101
- <AnnouncementBarContext.Provider value={value}>
102
- {children}
103
- </AnnouncementBarContext.Provider>
99
+ }),
100
+ [announcementBar, isClosed, handleClose],
104
101
  );
105
- };
106
-
107
- export const useAnnouncementBar = (): AnnouncementBarAPI => {
108
- const api = useContext(AnnouncementBarContext);
102
+ }
103
+
104
+ export function AnnouncementBarProvider({
105
+ children,
106
+ }: {
107
+ children: ReactNode;
108
+ }): JSX.Element {
109
+ const value = useContextValue();
110
+ return <Context.Provider value={value}>{children}</Context.Provider>;
111
+ }
112
+
113
+ export function useAnnouncementBar(): ContextValue {
114
+ const api = useContext(Context);
109
115
  if (!api) {
110
- throw new Error(
111
- 'useAnnouncementBar(): AnnouncementBar not found in React context: make sure to use the AnnouncementBarProvider on top of the tree',
112
- );
116
+ throw new ReactContextError('AnnouncementBarProvider');
113
117
  }
114
118
  return api;
115
- };
119
+ }
@@ -0,0 +1,80 @@
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, {useMemo, type ReactNode, useContext} from 'react';
9
+ import {ReactContextError} from '../utils/reactUtils';
10
+
11
+ import type {PropBlogPostContent} from '@docusaurus/plugin-content-blog';
12
+
13
+ /**
14
+ * The React context value returned by the `useBlogPost()` hook.
15
+ * It contains useful data related to the currently browsed blog post.
16
+ */
17
+ export type BlogPostContextValue = Pick<
18
+ PropBlogPostContent,
19
+ 'metadata' | 'frontMatter' | 'assets' | 'toc'
20
+ > & {
21
+ readonly isBlogPostPage: boolean;
22
+ };
23
+
24
+ const Context = React.createContext<BlogPostContextValue | null>(null);
25
+
26
+ /**
27
+ * Note: we don't use `PropBlogPostContent` as context value on purpose. Metadata is
28
+ * currently stored inside the MDX component, but we may want to change that in
29
+ * the future.
30
+ */
31
+ function useContextValue({
32
+ content,
33
+ isBlogPostPage,
34
+ }: {
35
+ content: PropBlogPostContent;
36
+ isBlogPostPage: boolean;
37
+ }): BlogPostContextValue {
38
+ return useMemo(
39
+ () => ({
40
+ metadata: content.metadata,
41
+ frontMatter: content.frontMatter,
42
+ assets: content.assets,
43
+ toc: content.toc,
44
+ isBlogPostPage,
45
+ }),
46
+ [content, isBlogPostPage],
47
+ );
48
+ }
49
+
50
+ /**
51
+ * This is a very thin layer around the `content` received from the MDX loader.
52
+ * It provides metadata about the blog post to the children tree.
53
+ */
54
+ export function BlogPostProvider({
55
+ children,
56
+ content,
57
+ isBlogPostPage = false,
58
+ }: {
59
+ children: ReactNode;
60
+ content: PropBlogPostContent;
61
+ isBlogPostPage?: boolean;
62
+ }): JSX.Element {
63
+ const contextValue = useContextValue({content, isBlogPostPage});
64
+ return <Context.Provider value={contextValue}>{children}</Context.Provider>;
65
+ }
66
+
67
+ /**
68
+ * Returns the data of the currently browsed blog post. Gives access to
69
+ * front matter, metadata, TOC, etc.
70
+ * When swizzling a low-level component (e.g. the "Edit this page" link)
71
+ * and you need some extra metadata, you don't have to drill the props
72
+ * all the way through the component tree: simply use this hook instead.
73
+ */
74
+ export function useBlogPost(): BlogPostContextValue {
75
+ const blogPost = useContext(Context);
76
+ if (blogPost === null) {
77
+ throw new ReactContextError('BlogPostProvider');
78
+ }
79
+ return blogPost;
80
+ }