@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.
Files changed (261) hide show
  1. package/README.md +2 -2
  2. package/lib/components/Collapsible/index.d.ts +59 -0
  3. package/lib/components/Collapsible/index.d.ts.map +1 -0
  4. package/lib/components/Collapsible/index.js +145 -0
  5. package/lib/components/Collapsible/index.js.map +1 -0
  6. package/lib/components/Details/index.d.ts +20 -0
  7. package/lib/components/Details/index.d.ts.map +1 -0
  8. package/lib/components/Details/index.js +86 -0
  9. package/lib/components/Details/index.js.map +1 -0
  10. package/lib/components/Details/styles.module.css +66 -0
  11. package/lib/components/ThemedComponent/index.d.ts +31 -0
  12. package/lib/components/ThemedComponent/index.d.ts.map +1 -0
  13. package/lib/components/ThemedComponent/index.js +47 -0
  14. package/lib/components/ThemedComponent/index.js.map +1 -0
  15. package/lib/components/ThemedComponent/styles.module.css +26 -0
  16. package/lib/contexts/announcementBar.d.ts +21 -0
  17. package/lib/contexts/announcementBar.d.ts.map +1 -0
  18. package/lib/contexts/announcementBar.js +72 -0
  19. package/lib/contexts/announcementBar.js.map +1 -0
  20. package/lib/contexts/colorMode.d.ts +23 -0
  21. package/lib/contexts/colorMode.d.ts.map +1 -0
  22. package/lib/contexts/colorMode.js +163 -0
  23. package/lib/contexts/colorMode.js.map +1 -0
  24. package/lib/contexts/navbarMobileSidebar.d.ts +31 -0
  25. package/lib/contexts/navbarMobileSidebar.d.ts.map +1 -0
  26. package/lib/contexts/navbarMobileSidebar.js +65 -0
  27. package/lib/contexts/navbarMobileSidebar.js.map +1 -0
  28. package/lib/contexts/navbarSecondaryMenu/content.d.ts +37 -0
  29. package/lib/contexts/navbarSecondaryMenu/content.d.ts.map +1 -0
  30. package/lib/contexts/navbarSecondaryMenu/content.js +50 -0
  31. package/lib/contexts/navbarSecondaryMenu/content.js.map +1 -0
  32. package/lib/contexts/navbarSecondaryMenu/display.d.ts +24 -0
  33. package/lib/contexts/navbarSecondaryMenu/display.d.ts.map +1 -0
  34. package/lib/contexts/navbarSecondaryMenu/display.js +62 -0
  35. package/lib/contexts/navbarSecondaryMenu/display.js.map +1 -0
  36. package/lib/hooks/useBackToTopButton.d.ts +27 -0
  37. package/lib/hooks/useBackToTopButton.d.ts.map +1 -0
  38. package/lib/hooks/useBackToTopButton.js +50 -0
  39. package/lib/hooks/useBackToTopButton.js.map +1 -0
  40. package/lib/hooks/useCodeWordWrap.d.ts +15 -0
  41. package/lib/hooks/useCodeWordWrap.d.ts.map +1 -0
  42. package/lib/hooks/useCodeWordWrap.js +67 -0
  43. package/lib/hooks/useCodeWordWrap.js.map +1 -0
  44. package/lib/hooks/useHideableNavbar.d.ts +17 -0
  45. package/lib/hooks/useHideableNavbar.d.ts.map +1 -0
  46. package/lib/hooks/useHideableNavbar.js +65 -0
  47. package/lib/hooks/useHideableNavbar.js.map +1 -0
  48. package/lib/hooks/useLockBodyScroll.d.ts +12 -0
  49. package/lib/hooks/useLockBodyScroll.d.ts.map +1 -0
  50. package/lib/hooks/useLockBodyScroll.js +20 -0
  51. package/lib/hooks/useLockBodyScroll.js.map +1 -0
  52. package/lib/hooks/useMutationObserver.d.ts +4 -0
  53. package/lib/hooks/useMutationObserver.d.ts.map +1 -0
  54. package/lib/hooks/useMutationObserver.js +29 -0
  55. package/lib/hooks/useMutationObserver.js.map +1 -0
  56. package/lib/hooks/usePrismTheme.d.ts +13 -0
  57. package/lib/hooks/usePrismTheme.d.ts.map +1 -0
  58. package/lib/hooks/usePrismTheme.js +21 -0
  59. package/lib/hooks/usePrismTheme.js.map +1 -0
  60. package/lib/hooks/useTOCHighlight.d.ts +25 -0
  61. package/lib/hooks/useTOCHighlight.d.ts.map +1 -0
  62. package/lib/hooks/useTOCHighlight.js +130 -0
  63. package/lib/hooks/useTOCHighlight.js.map +1 -0
  64. package/lib/hooks/useWindowSize.d.ts +27 -0
  65. package/lib/hooks/useWindowSize.d.ts.map +1 -0
  66. package/lib/hooks/useWindowSize.js +49 -0
  67. package/lib/hooks/useWindowSize.js.map +1 -0
  68. package/lib/index.d.ts +30 -0
  69. package/lib/index.d.ts.map +1 -0
  70. package/lib/index.js +37 -0
  71. package/lib/index.js.map +1 -0
  72. package/lib/internal.d.ts +35 -0
  73. package/lib/internal.d.ts.map +1 -0
  74. package/lib/internal.js +45 -0
  75. package/lib/internal.js.map +1 -0
  76. package/lib/translations/blogTranslations.d.ts +20 -0
  77. package/lib/translations/blogTranslations.d.ts.map +1 -0
  78. package/lib/translations/blogTranslations.js +52 -0
  79. package/lib/translations/blogTranslations.js.map +1 -0
  80. package/lib/translations/contentVisibilityTranslations.d.ts +12 -0
  81. package/lib/translations/contentVisibilityTranslations.d.ts.map +1 -0
  82. package/lib/translations/contentVisibilityTranslations.js +30 -0
  83. package/lib/translations/contentVisibilityTranslations.js.map +1 -0
  84. package/lib/translations/docsTranslations.d.ts +8 -0
  85. package/lib/translations/docsTranslations.d.ts.map +1 -0
  86. package/lib/translations/docsTranslations.js +17 -0
  87. package/lib/translations/docsTranslations.js.map +1 -0
  88. package/lib/utils/IntlUtils.d.ts +2 -0
  89. package/lib/utils/IntlUtils.d.ts.map +1 -0
  90. package/lib/utils/IntlUtils.js +20 -0
  91. package/lib/utils/IntlUtils.js.map +1 -0
  92. package/lib/utils/ThemeClassNames.d.ts +99 -0
  93. package/lib/utils/ThemeClassNames.d.ts.map +1 -0
  94. package/lib/utils/ThemeClassNames.js +107 -0
  95. package/lib/utils/ThemeClassNames.js.map +1 -0
  96. package/lib/utils/accessibilityUtils.d.ts +8 -0
  97. package/lib/utils/accessibilityUtils.d.ts.map +1 -0
  98. package/lib/utils/accessibilityUtils.js +10 -0
  99. package/lib/utils/accessibilityUtils.js.map +1 -0
  100. package/lib/utils/admonitionUtils.d.ts +12 -0
  101. package/lib/utils/admonitionUtils.d.ts.map +1 -0
  102. package/lib/utils/admonitionUtils.js +32 -0
  103. package/lib/utils/admonitionUtils.js.map +1 -0
  104. package/lib/utils/anchorUtils.d.ts +16 -0
  105. package/lib/utils/anchorUtils.d.ts.map +1 -0
  106. package/lib/utils/anchorUtils.js +26 -0
  107. package/lib/utils/anchorUtils.js.map +1 -0
  108. package/lib/utils/anchorUtils.module.css +14 -0
  109. package/lib/utils/codeBlockUtils.d.ts +101 -0
  110. package/lib/utils/codeBlockUtils.d.ts.map +1 -0
  111. package/lib/utils/codeBlockUtils.js +310 -0
  112. package/lib/utils/codeBlockUtils.js.map +1 -0
  113. package/lib/utils/emojiUtils.d.ts +20 -0
  114. package/lib/utils/emojiUtils.d.ts.map +1 -0
  115. package/lib/utils/emojiUtils.js +32 -0
  116. package/lib/utils/emojiUtils.js.map +1 -0
  117. package/lib/utils/errorBoundaryUtils.d.ts +31 -0
  118. package/lib/utils/errorBoundaryUtils.d.ts.map +1 -0
  119. package/lib/utils/errorBoundaryUtils.js +48 -0
  120. package/lib/utils/errorBoundaryUtils.js.map +1 -0
  121. package/lib/utils/errorBoundaryUtils.module.css +16 -0
  122. package/lib/utils/footerUtils.d.ts +13 -0
  123. package/lib/utils/footerUtils.d.ts.map +1 -0
  124. package/lib/utils/footerUtils.js +14 -0
  125. package/lib/utils/footerUtils.js.map +1 -0
  126. package/lib/utils/historyUtils.d.ts +39 -0
  127. package/lib/utils/historyUtils.d.ts.map +1 -0
  128. package/lib/utils/historyUtils.js +148 -0
  129. package/lib/utils/historyUtils.js.map +1 -0
  130. package/lib/utils/jsUtils.d.ts +24 -0
  131. package/lib/utils/jsUtils.d.ts.map +1 -0
  132. package/lib/utils/jsUtils.js +43 -0
  133. package/lib/utils/jsUtils.js.map +1 -0
  134. package/lib/utils/metadataUtils.d.ts +38 -0
  135. package/lib/utils/metadataUtils.d.ts.map +1 -0
  136. package/lib/utils/metadataUtils.js +87 -0
  137. package/lib/utils/metadataUtils.js.map +1 -0
  138. package/lib/utils/navbarUtils.d.ts +21 -0
  139. package/lib/utils/navbarUtils.d.ts.map +1 -0
  140. package/lib/utils/navbarUtils.js +35 -0
  141. package/lib/utils/navbarUtils.js.map +1 -0
  142. package/lib/utils/reactUtils.d.ts +60 -0
  143. package/lib/utils/reactUtils.d.ts.map +1 -0
  144. package/lib/utils/reactUtils.js +91 -0
  145. package/lib/utils/reactUtils.js.map +1 -0
  146. package/lib/utils/regexpUtils.d.ts +12 -0
  147. package/lib/utils/regexpUtils.d.ts.map +1 -0
  148. package/lib/utils/regexpUtils.js +18 -0
  149. package/lib/utils/regexpUtils.js.map +1 -0
  150. package/lib/utils/routesUtils.d.ts +26 -0
  151. package/lib/utils/routesUtils.d.ts.map +1 -0
  152. package/lib/utils/routesUtils.js +54 -0
  153. package/lib/utils/routesUtils.js.map +1 -0
  154. package/lib/utils/scrollUtils.d.ts +83 -0
  155. package/lib/utils/scrollUtils.d.ts.map +1 -0
  156. package/lib/utils/scrollUtils.js +201 -0
  157. package/lib/utils/scrollUtils.js.map +1 -0
  158. package/lib/utils/searchUtils.d.ts +8 -0
  159. package/lib/utils/searchUtils.d.ts.map +1 -0
  160. package/lib/utils/searchUtils.js +8 -0
  161. package/lib/utils/searchUtils.js.map +1 -0
  162. package/lib/utils/skipToContentUtils.d.ts +20 -0
  163. package/lib/utils/skipToContentUtils.d.ts.map +1 -0
  164. package/lib/utils/skipToContentUtils.js +75 -0
  165. package/lib/utils/skipToContentUtils.js.map +1 -0
  166. package/lib/utils/storageUtils.d.ts +36 -0
  167. package/lib/utils/storageUtils.d.ts.map +1 -0
  168. package/lib/utils/storageUtils.js +193 -0
  169. package/lib/utils/storageUtils.js.map +1 -0
  170. package/lib/utils/tabsUtils.d.ts +55 -0
  171. package/lib/utils/tabsUtils.d.ts.map +1 -0
  172. package/lib/utils/tabsUtils.js +179 -0
  173. package/lib/utils/tabsUtils.js.map +1 -0
  174. package/lib/utils/tagsUtils.d.ts +20 -0
  175. package/lib/utils/tagsUtils.d.ts.map +1 -0
  176. package/lib/utils/tagsUtils.js +41 -0
  177. package/lib/utils/tagsUtils.js.map +1 -0
  178. package/lib/utils/titleFormatterUtils.d.ts +59 -0
  179. package/lib/utils/titleFormatterUtils.d.ts.map +1 -0
  180. package/lib/utils/titleFormatterUtils.js +49 -0
  181. package/lib/utils/titleFormatterUtils.js.map +1 -0
  182. package/lib/utils/tocUtils.d.ts +36 -0
  183. package/lib/utils/tocUtils.d.ts.map +1 -0
  184. package/lib/utils/tocUtils.js +84 -0
  185. package/lib/utils/tocUtils.js.map +1 -0
  186. package/lib/utils/useAlternatePageUtils.d.ts +32 -0
  187. package/lib/utils/useAlternatePageUtils.d.ts.map +1 -0
  188. package/lib/utils/useAlternatePageUtils.js +42 -0
  189. package/lib/utils/useAlternatePageUtils.js.map +1 -0
  190. package/lib/utils/useLocalPathname.d.ts +13 -0
  191. package/lib/utils/useLocalPathname.d.ts.map +1 -0
  192. package/lib/utils/useLocalPathname.js +19 -0
  193. package/lib/utils/useLocalPathname.js.map +1 -0
  194. package/lib/utils/useLocationChange.d.ts +17 -0
  195. package/lib/utils/useLocationChange.d.ts.map +1 -0
  196. package/lib/utils/useLocationChange.js +31 -0
  197. package/lib/utils/useLocationChange.js.map +1 -0
  198. package/lib/utils/usePluralForm.d.ts +21 -0
  199. package/lib/utils/usePluralForm.d.ts.map +1 -0
  200. package/lib/utils/usePluralForm.js +93 -0
  201. package/lib/utils/usePluralForm.js.map +1 -0
  202. package/lib/utils/useThemeConfig.d.ts +120 -0
  203. package/lib/utils/useThemeConfig.d.ts.map +1 -0
  204. package/lib/utils/useThemeConfig.js +14 -0
  205. package/lib/utils/useThemeConfig.js.map +1 -0
  206. package/package.json +58 -4
  207. package/src/components/Collapsible/index.tsx +250 -0
  208. package/src/components/Details/index.tsx +130 -0
  209. package/src/components/Details/styles.module.css +66 -0
  210. package/src/components/ThemedComponent/index.tsx +75 -0
  211. package/src/components/ThemedComponent/styles.module.css +26 -0
  212. package/src/contexts/announcementBar.tsx +117 -0
  213. package/src/contexts/colorMode.tsx +257 -0
  214. package/src/contexts/navbarMobileSidebar.tsx +119 -0
  215. package/src/contexts/navbarSecondaryMenu/content.tsx +100 -0
  216. package/src/contexts/navbarSecondaryMenu/display.tsx +102 -0
  217. package/src/hooks/useBackToTopButton.ts +73 -0
  218. package/src/hooks/useCodeWordWrap.ts +107 -0
  219. package/src/hooks/useHideableNavbar.ts +81 -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/useTOCHighlight.ts +189 -0
  224. package/src/hooks/useWindowSize.ts +67 -0
  225. package/src/index.ts +112 -0
  226. package/src/internal.ts +107 -0
  227. package/src/translations/blogTranslations.tsx +89 -0
  228. package/src/translations/contentVisibilityTranslations.tsx +51 -0
  229. package/src/translations/docsTranslations.tsx +28 -0
  230. package/src/types.d.ts +8 -0
  231. package/src/utils/IntlUtils.ts +27 -0
  232. package/src/utils/ThemeClassNames.ts +119 -0
  233. package/src/utils/accessibilityUtils.ts +10 -0
  234. package/src/utils/admonitionUtils.tsx +44 -0
  235. package/src/utils/anchorUtils.module.css +14 -0
  236. package/src/utils/anchorUtils.ts +31 -0
  237. package/src/utils/codeBlockUtils.tsx +494 -0
  238. package/src/utils/emojiUtils.ts +40 -0
  239. package/src/utils/errorBoundaryUtils.module.css +16 -0
  240. package/src/utils/errorBoundaryUtils.tsx +71 -0
  241. package/src/utils/footerUtils.ts +18 -0
  242. package/src/utils/historyUtils.ts +199 -0
  243. package/src/utils/jsUtils.ts +54 -0
  244. package/src/utils/metadataUtils.tsx +145 -0
  245. package/src/utils/navbarUtils.tsx +45 -0
  246. package/src/utils/reactUtils.tsx +120 -0
  247. package/src/utils/regexpUtils.ts +24 -0
  248. package/src/utils/routesUtils.ts +75 -0
  249. package/src/utils/scrollUtils.tsx +303 -0
  250. package/src/utils/searchUtils.ts +8 -0
  251. package/src/utils/skipToContentUtils.tsx +108 -0
  252. package/src/utils/storageUtils.ts +260 -0
  253. package/src/utils/tabsUtils.tsx +307 -0
  254. package/src/utils/tagsUtils.tsx +61 -0
  255. package/src/utils/titleFormatterUtils.tsx +120 -0
  256. package/src/utils/tocUtils.ts +119 -0
  257. package/src/utils/useAlternatePageUtils.ts +80 -0
  258. package/src/utils/useLocalPathname.ts +22 -0
  259. package/src/utils/useLocationChange.ts +41 -0
  260. package/src/utils/usePluralForm.ts +131 -0
  261. package/src/utils/useThemeConfig.ts +147 -0
@@ -0,0 +1,73 @@
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 {useRef, useState} from 'react';
9
+ import {useScrollPosition, useSmoothScrollTo} from '../utils/scrollUtils';
10
+ import {useLocationChange} from '../utils/useLocationChange';
11
+
12
+ /** Wires the logic for the back to top button. */
13
+ export function useBackToTopButton({
14
+ threshold,
15
+ }: {
16
+ /**
17
+ * The minimum vertical scroll position, above which a scroll-up would not
18
+ * cause `shown` to become `true`. This is because BTT is only useful if the
19
+ * user is far down the page.
20
+ */
21
+ threshold: number;
22
+ }): {
23
+ /**
24
+ * Whether the button should be displayed. We only show if the user has
25
+ * scrolled up and is on a vertical position greater than `threshold`.
26
+ */
27
+ shown: boolean;
28
+ /**
29
+ * A (memoized) handle for starting the scroll, which you can directly plug
30
+ * into the props.
31
+ */
32
+ scrollToTop: () => void;
33
+ } {
34
+ const [shown, setShown] = useState(false);
35
+ const isFocusedAnchor = useRef(false);
36
+ const {startScroll, cancelScroll} = useSmoothScrollTo();
37
+
38
+ useScrollPosition(({scrollY: scrollTop}, lastPosition) => {
39
+ const lastScrollTop = lastPosition?.scrollY;
40
+ // Component is just being mounted. Not really a scroll event from the user.
41
+ // Ignore it.
42
+ if (!lastScrollTop) {
43
+ return;
44
+ }
45
+ if (isFocusedAnchor.current) {
46
+ // This scroll position change is triggered by navigating to an anchor.
47
+ // Ignore it.
48
+ isFocusedAnchor.current = false;
49
+ } else if (scrollTop >= lastScrollTop) {
50
+ // The user has scrolled down to "fight against" the animation. Cancel any
51
+ // animation under progress.
52
+ cancelScroll();
53
+ setShown(false);
54
+ } else if (scrollTop < threshold) {
55
+ // Scrolled to the minimum position; hide the button.
56
+ setShown(false);
57
+ } else if (
58
+ scrollTop + window.innerHeight <
59
+ document.documentElement.scrollHeight
60
+ ) {
61
+ setShown(true);
62
+ }
63
+ });
64
+
65
+ useLocationChange((locationChangeEvent) => {
66
+ if (locationChangeEvent.location.hash) {
67
+ isFocusedAnchor.current = true;
68
+ setShown(false);
69
+ }
70
+ });
71
+
72
+ return {shown, scrollToTop: () => startScroll(0)};
73
+ }
@@ -0,0 +1,107 @@
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
+ import type {RefObject} from 'react';
8
+ import {useState, useCallback, useEffect, useRef} from 'react';
9
+ import {useMutationObserver} from './useMutationObserver';
10
+
11
+ // Callback fires when the "hidden" attribute of a tabpanel changes
12
+ // See https://github.com/facebook/docusaurus/pull/7485
13
+ function useTabBecameVisibleCallback(
14
+ codeBlockRef: RefObject<HTMLPreElement | null>,
15
+ callback: () => void,
16
+ ) {
17
+ const [hiddenTabElement, setHiddenTabElement] = useState<
18
+ Element | null | undefined
19
+ >();
20
+
21
+ const updateHiddenTabElement = useCallback(() => {
22
+ // No need to observe non-hidden tabs
23
+ // + we want to force a re-render when a tab becomes visible
24
+ setHiddenTabElement(
25
+ codeBlockRef.current?.closest('[role=tabpanel][hidden]'),
26
+ );
27
+ }, [codeBlockRef, setHiddenTabElement]);
28
+
29
+ useEffect(() => {
30
+ updateHiddenTabElement();
31
+ }, [updateHiddenTabElement]);
32
+
33
+ useMutationObserver(
34
+ hiddenTabElement,
35
+ (mutations: MutationRecord[]) => {
36
+ mutations.forEach((mutation) => {
37
+ if (
38
+ mutation.type === 'attributes' &&
39
+ mutation.attributeName === 'hidden'
40
+ ) {
41
+ callback();
42
+ updateHiddenTabElement();
43
+ }
44
+ });
45
+ },
46
+ {
47
+ attributes: true,
48
+ characterData: false,
49
+ childList: false,
50
+ subtree: false,
51
+ },
52
+ );
53
+ }
54
+
55
+ export type WordWrap = {
56
+ readonly codeBlockRef: RefObject<HTMLPreElement | null>;
57
+ readonly isEnabled: boolean;
58
+ readonly isCodeScrollable: boolean;
59
+ readonly toggle: () => void;
60
+ };
61
+
62
+ export function useCodeWordWrap(): WordWrap {
63
+ const [isEnabled, setIsEnabled] = useState(false);
64
+ const [isCodeScrollable, setIsCodeScrollable] = useState<boolean>(false);
65
+ const codeBlockRef = useRef<HTMLPreElement>(null);
66
+
67
+ const toggle = useCallback(() => {
68
+ const codeElement = codeBlockRef.current!.querySelector('code')!;
69
+
70
+ if (isEnabled) {
71
+ codeElement.removeAttribute('style');
72
+ } else {
73
+ codeElement.style.whiteSpace = 'pre-wrap';
74
+ // When code wrap is enabled, we want to avoid a scrollbar in any case
75
+ // Ensure that very very long words/strings/tokens still wrap
76
+ codeElement.style.overflowWrap = 'anywhere';
77
+ }
78
+
79
+ setIsEnabled((value) => !value);
80
+ }, [codeBlockRef, isEnabled]);
81
+
82
+ const updateCodeIsScrollable = useCallback(() => {
83
+ const {scrollWidth, clientWidth} = codeBlockRef.current!;
84
+ const isScrollable =
85
+ scrollWidth > clientWidth ||
86
+ codeBlockRef.current!.querySelector('code')!.hasAttribute('style');
87
+ setIsCodeScrollable(isScrollable);
88
+ }, [codeBlockRef]);
89
+
90
+ useTabBecameVisibleCallback(codeBlockRef, updateCodeIsScrollable);
91
+
92
+ useEffect(() => {
93
+ updateCodeIsScrollable();
94
+ }, [isEnabled, updateCodeIsScrollable]);
95
+
96
+ useEffect(() => {
97
+ window.addEventListener('resize', updateCodeIsScrollable, {
98
+ passive: true,
99
+ });
100
+
101
+ return () => {
102
+ window.removeEventListener('resize', updateCodeIsScrollable);
103
+ };
104
+ }, [updateCodeIsScrollable]);
105
+
106
+ return {codeBlockRef, isEnabled, isCodeScrollable, toggle};
107
+ }
@@ -0,0 +1,81 @@
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 {useState, useCallback, useRef} from 'react';
9
+ import {useLocationChange} from '../utils/useLocationChange';
10
+ import {useScrollPosition} from '../utils/scrollUtils';
11
+
12
+ /**
13
+ * Wires the imperative logic of a hideable navbar.
14
+ * @param hideOnScroll If `false`, this hook is basically a no-op.
15
+ */
16
+ export function useHideableNavbar(hideOnScroll: boolean): {
17
+ /** A ref to the navbar component. Plug this into the actual element. */
18
+ readonly navbarRef: (node: HTMLElement | null) => void;
19
+ /** If `false`, the navbar component should not be rendered. */
20
+ readonly isNavbarVisible: boolean;
21
+ } {
22
+ const [isNavbarVisible, setIsNavbarVisible] = useState(hideOnScroll);
23
+ const isFocusedAnchor = useRef(false);
24
+ const navbarHeight = useRef(0);
25
+ const navbarRef = useCallback((node: HTMLElement | null) => {
26
+ if (node !== null) {
27
+ navbarHeight.current = node.getBoundingClientRect().height;
28
+ }
29
+ }, []);
30
+
31
+ useScrollPosition(({scrollY: scrollTop}, lastPosition) => {
32
+ if (!hideOnScroll) {
33
+ return;
34
+ }
35
+
36
+ // Needed mostly for handling rubber band scrolling.
37
+ // See https://github.com/facebook/docusaurus/pull/5721
38
+ if (scrollTop < navbarHeight.current) {
39
+ setIsNavbarVisible(true);
40
+ return;
41
+ }
42
+
43
+ if (isFocusedAnchor.current) {
44
+ isFocusedAnchor.current = false;
45
+ return;
46
+ }
47
+
48
+ const lastScrollTop = lastPosition?.scrollY;
49
+ const documentHeight =
50
+ document.documentElement.scrollHeight - navbarHeight.current;
51
+ const windowHeight = window.innerHeight;
52
+
53
+ if (lastScrollTop && scrollTop >= lastScrollTop) {
54
+ setIsNavbarVisible(false);
55
+ } else if (scrollTop + windowHeight < documentHeight) {
56
+ setIsNavbarVisible(true);
57
+ }
58
+ });
59
+
60
+ useLocationChange((locationChangeEvent) => {
61
+ if (!hideOnScroll) {
62
+ return;
63
+ }
64
+
65
+ // See https://github.com/facebook/docusaurus/pull/8059#issuecomment-1239639480
66
+ const currentHash = locationChangeEvent.location.hash;
67
+ const currentHashAnchor = currentHash
68
+ ? document.getElementById(currentHash.substring(1))
69
+ : undefined;
70
+
71
+ if (currentHashAnchor) {
72
+ isFocusedAnchor.current = true;
73
+ setIsNavbarVisible(false);
74
+ return;
75
+ }
76
+
77
+ setIsNavbarVisible(true);
78
+ });
79
+
80
+ return {navbarRef, isNavbarVisible};
81
+ }
@@ -0,0 +1,21 @@
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 {useEffect} from 'react';
9
+
10
+ /**
11
+ * Side-effect that locks the document body's scroll throughout the lifetime of
12
+ * the containing component. e.g. when the mobile sidebar is expanded.
13
+ */
14
+ export function useLockBodyScroll(lock: boolean = true): void {
15
+ useEffect(() => {
16
+ document.body.style.overflow = lock ? 'hidden' : 'visible';
17
+ return () => {
18
+ document.body.style.overflow = 'visible';
19
+ };
20
+ }, [lock]);
21
+ }
@@ -0,0 +1,38 @@
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
+ import {useEffect} from 'react';
8
+ import {useEvent, useShallowMemoObject} from '../utils/reactUtils';
9
+
10
+ type Options = MutationObserverInit;
11
+
12
+ const DefaultOptions: Options = {
13
+ attributes: true,
14
+ characterData: true,
15
+ childList: true,
16
+ subtree: true,
17
+ };
18
+
19
+ export function useMutationObserver(
20
+ target: Element | undefined | null,
21
+ callback: MutationCallback,
22
+ options: Options = DefaultOptions,
23
+ ): void {
24
+ const stableCallback = useEvent(callback);
25
+
26
+ // MutationObserver options are not nested much
27
+ // so this should be to memo options in 99%
28
+ // TODO handle options.attributeFilter array
29
+ const stableOptions: Options = useShallowMemoObject(options);
30
+
31
+ useEffect(() => {
32
+ const observer = new MutationObserver(stableCallback);
33
+ if (target) {
34
+ observer.observe(target, stableOptions);
35
+ }
36
+ return () => observer.disconnect();
37
+ }, [target, stableCallback, stableOptions]);
38
+ }
@@ -0,0 +1,24 @@
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 {useColorMode} from '../contexts/colorMode';
9
+ import {useThemeConfig} from '../utils/useThemeConfig';
10
+ import type {PrismTheme} from 'prism-react-renderer';
11
+
12
+ /**
13
+ * Returns a color-mode-dependent Prism theme: whatever the user specified in
14
+ * the config. Falls back to `palenight`.
15
+ */
16
+ export function usePrismTheme(): PrismTheme {
17
+ const {prism} = useThemeConfig();
18
+ const {colorMode} = useColorMode();
19
+ const lightModeTheme = prism.theme;
20
+ const darkModeTheme = prism.darkTheme || lightModeTheme;
21
+ const prismTheme = colorMode === 'dark' ? darkModeTheme : lightModeTheme;
22
+
23
+ return prismTheme;
24
+ }
@@ -0,0 +1,189 @@
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 {useEffect, useRef} from 'react';
9
+ import {useThemeConfig} from '../utils/useThemeConfig';
10
+
11
+ // TODO make the hardcoded theme-classic classnames configurable (or add them
12
+ // to ThemeClassNames?)
13
+
14
+ /**
15
+ * If the anchor has no height and is just a "marker" in the DOM; we'll use the
16
+ * parent (normally the link text) rect boundaries instead
17
+ */
18
+ function getVisibleBoundingClientRect(element: HTMLElement): DOMRect {
19
+ const rect = element.getBoundingClientRect();
20
+ const hasNoHeight = rect.top === rect.bottom;
21
+ if (hasNoHeight) {
22
+ return getVisibleBoundingClientRect(element.parentNode as HTMLElement);
23
+ }
24
+ return rect;
25
+ }
26
+
27
+ /**
28
+ * Considering we divide viewport into 2 zones of each 50vh, this returns true
29
+ * if an element is in the first zone (i.e., appear in viewport, near the top)
30
+ */
31
+ function isInViewportTopHalf(boundingRect: DOMRect) {
32
+ return boundingRect.top > 0 && boundingRect.bottom < window.innerHeight / 2;
33
+ }
34
+
35
+ function getAnchors({
36
+ minHeadingLevel,
37
+ maxHeadingLevel,
38
+ }: {
39
+ minHeadingLevel: number;
40
+ maxHeadingLevel: number;
41
+ }): HTMLElement[] {
42
+ const selectors = [];
43
+ for (let i = minHeadingLevel; i <= maxHeadingLevel; i += 1) {
44
+ selectors.push(`h${i}.anchor`);
45
+ }
46
+ return Array.from(document.querySelectorAll(selectors.join()));
47
+ }
48
+
49
+ function getActiveAnchor(
50
+ anchors: HTMLElement[],
51
+ {
52
+ anchorTopOffset,
53
+ }: {
54
+ anchorTopOffset: number;
55
+ },
56
+ ): Element | null {
57
+ // Naming is hard: The "nextVisibleAnchor" is the first anchor that appear
58
+ // under the viewport top boundary. It does not mean this anchor is visible
59
+ // yet, but if user continues scrolling down, it will be the first to become
60
+ // visible
61
+ const nextVisibleAnchor = anchors.find((anchor) => {
62
+ const boundingRect = getVisibleBoundingClientRect(anchor);
63
+ return boundingRect.top >= anchorTopOffset;
64
+ });
65
+
66
+ if (nextVisibleAnchor) {
67
+ const boundingRect = getVisibleBoundingClientRect(nextVisibleAnchor);
68
+ // If anchor is in the top half of the viewport: it is the one we consider
69
+ // "active" (unless it's too close to the top and and soon to be scrolled
70
+ // outside viewport)
71
+ if (isInViewportTopHalf(boundingRect)) {
72
+ return nextVisibleAnchor;
73
+ }
74
+ // If anchor is in the bottom half of the viewport, or under the viewport,
75
+ // we consider the active anchor is the previous one. This is because the
76
+ // main text appearing in the user screen mostly belong to the previous
77
+ // anchor. Returns null for the first anchor, see
78
+ // https://github.com/facebook/docusaurus/issues/5318
79
+ return anchors[anchors.indexOf(nextVisibleAnchor) - 1] ?? null;
80
+ }
81
+ // No anchor under viewport top (i.e. we are at the bottom of the page),
82
+ // highlight the last anchor found
83
+ return anchors[anchors.length - 1] ?? null;
84
+ }
85
+
86
+ function getLinkAnchorValue(link: HTMLAnchorElement): string {
87
+ return decodeURIComponent(link.href.substring(link.href.indexOf('#') + 1));
88
+ }
89
+
90
+ function getLinks(linkClassName: string) {
91
+ return Array.from(
92
+ document.getElementsByClassName(linkClassName),
93
+ ) as HTMLAnchorElement[];
94
+ }
95
+
96
+ function getNavbarHeight(): number {
97
+ // Not ideal to obtain actual height this way
98
+ // Using TS ! (not ?) because otherwise a bad selector would be un-noticed
99
+ return document.querySelector('.navbar')!.clientHeight;
100
+ }
101
+
102
+ function useAnchorTopOffsetRef() {
103
+ const anchorTopOffsetRef = useRef<number>(0);
104
+ const {
105
+ navbar: {hideOnScroll},
106
+ } = useThemeConfig();
107
+
108
+ useEffect(() => {
109
+ anchorTopOffsetRef.current = hideOnScroll ? 0 : getNavbarHeight();
110
+ }, [hideOnScroll]);
111
+
112
+ return anchorTopOffsetRef;
113
+ }
114
+
115
+ export type TOCHighlightConfig = {
116
+ /** A class name that all TOC links share. */
117
+ linkClassName: string;
118
+ /** The class name applied to the active (highlighted) link. */
119
+ linkActiveClassName: string;
120
+ /**
121
+ * The minimum heading level that the TOC includes. Only headings that are in
122
+ * this range will be eligible as "active heading".
123
+ */
124
+ minHeadingLevel: number;
125
+ /** @see {@link TOCHighlightConfig.minHeadingLevel} */
126
+ maxHeadingLevel: number;
127
+ };
128
+
129
+ /**
130
+ * Side-effect that applies the active class name to the TOC heading that the
131
+ * user is currently viewing. Disabled when `config` is undefined.
132
+ */
133
+ export function useTOCHighlight(config: TOCHighlightConfig | undefined): void {
134
+ const lastActiveLinkRef = useRef<HTMLAnchorElement | undefined>(undefined);
135
+
136
+ const anchorTopOffsetRef = useAnchorTopOffsetRef();
137
+
138
+ useEffect(() => {
139
+ if (!config) {
140
+ // No-op, highlighting is disabled
141
+ return () => {};
142
+ }
143
+
144
+ const {
145
+ linkClassName,
146
+ linkActiveClassName,
147
+ minHeadingLevel,
148
+ maxHeadingLevel,
149
+ } = config;
150
+
151
+ function updateLinkActiveClass(link: HTMLAnchorElement, active: boolean) {
152
+ if (active) {
153
+ if (lastActiveLinkRef.current && lastActiveLinkRef.current !== link) {
154
+ lastActiveLinkRef.current.classList.remove(linkActiveClassName);
155
+ }
156
+ link.classList.add(linkActiveClassName);
157
+ lastActiveLinkRef.current = link;
158
+ // link.scrollIntoView({block: 'nearest'});
159
+ } else {
160
+ link.classList.remove(linkActiveClassName);
161
+ }
162
+ }
163
+
164
+ function updateActiveLink() {
165
+ const links = getLinks(linkClassName);
166
+ const anchors = getAnchors({minHeadingLevel, maxHeadingLevel});
167
+ const activeAnchor = getActiveAnchor(anchors, {
168
+ anchorTopOffset: anchorTopOffsetRef.current,
169
+ });
170
+ const activeLink = links.find(
171
+ (link) => activeAnchor && activeAnchor.id === getLinkAnchorValue(link),
172
+ );
173
+
174
+ links.forEach((link) => {
175
+ updateLinkActiveClass(link, link === activeLink);
176
+ });
177
+ }
178
+
179
+ document.addEventListener('scroll', updateActiveLink);
180
+ document.addEventListener('resize', updateActiveLink);
181
+
182
+ updateActiveLink();
183
+
184
+ return () => {
185
+ document.removeEventListener('scroll', updateActiveLink);
186
+ document.removeEventListener('resize', updateActiveLink);
187
+ };
188
+ }, [config, anchorTopOffsetRef]);
189
+ }
@@ -0,0 +1,67 @@
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 {useSyncExternalStore} from 'react';
9
+
10
+ import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
11
+
12
+ const windowSizes = {
13
+ desktop: 'desktop',
14
+ mobile: 'mobile',
15
+ ssr: 'ssr',
16
+ } as const;
17
+
18
+ type WindowSize = keyof typeof windowSizes;
19
+
20
+ // Note: this value is also hardcoded in Infima
21
+ // Both JS and CSS must have the same value
22
+ // Updating this JS value alone is not enough
23
+ // See https://github.com/facebook/docusaurus/issues/9603
24
+ const DesktopBreakpoint = 996;
25
+
26
+ function getWindowSize(desktopBreakpoint: number): WindowSize {
27
+ if (!ExecutionEnvironment.canUseDOM) {
28
+ throw new Error(
29
+ 'getWindowSize() should only be called after React hydration',
30
+ );
31
+ }
32
+
33
+ return window.innerWidth > desktopBreakpoint
34
+ ? windowSizes.desktop
35
+ : windowSizes.mobile;
36
+ }
37
+
38
+ function subscribeToWindowResize(onChange: () => void): () => void {
39
+ window.addEventListener('resize', onChange);
40
+ return () => {
41
+ window.removeEventListener('resize', onChange);
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Gets the current window size as an enum value. We don't want it to return the
47
+ * actual width value, so that it only re-renders once a breakpoint is crossed.
48
+ *
49
+ * It may return `"ssr"`, which is very important to handle hydration FOUC or
50
+ * layout shifts. You have to handle it explicitly upfront. On the server, you
51
+ * may need to render BOTH the mobile/desktop elements (and hide one of them
52
+ * with mediaquery). We don't return `undefined` on purpose, to make it more
53
+ * explicit.
54
+ */
55
+ export function useWindowSize({
56
+ desktopBreakpoint = DesktopBreakpoint,
57
+ }: {
58
+ desktopBreakpoint?: number;
59
+ } = {}): WindowSize {
60
+ return useSyncExternalStore(
61
+ subscribeToWindowResize,
62
+ () => getWindowSize(desktopBreakpoint),
63
+ // super important to return a constant value to avoid hydration mismatch
64
+ // see https://github.com/facebook/docusaurus/issues/9379
65
+ () => windowSizes.ssr,
66
+ );
67
+ }