@docusaurus/theme-common 2.0.0-beta.ff31de0ff → 2.0.1

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 (269) hide show
  1. package/lib/components/Collapsible/index.d.ts +64 -0
  2. package/lib/components/Collapsible/index.d.ts.map +1 -0
  3. package/lib/components/Collapsible/index.js +150 -0
  4. package/lib/components/Collapsible/index.js.map +1 -0
  5. package/lib/components/Details/index.d.ts +17 -0
  6. package/lib/components/Details/index.d.ts.map +1 -0
  7. package/lib/components/Details/index.js +76 -0
  8. package/lib/components/Details/index.js.map +1 -0
  9. package/lib/components/Details/styles.module.css +62 -0
  10. package/lib/contexts/announcementBar.d.ts +22 -0
  11. package/lib/contexts/announcementBar.d.ts.map +1 -0
  12. package/lib/contexts/announcementBar.js +72 -0
  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/useChangeRoute.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 +16 -11
  104. package/lib/index.d.ts.map +1 -0
  105. package/lib/index.js +23 -10
  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 +58 -25
  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 +13 -0
  184. package/lib/utils/useLocalPathname.d.ts.map +1 -0
  185. package/lib/utils/useLocalPathname.js +19 -0
  186. package/lib/utils/useLocalPathname.js.map +1 -0
  187. package/lib/utils/useLocationChange.d.ts +17 -0
  188. package/lib/utils/useLocationChange.d.ts.map +1 -0
  189. package/lib/utils/useLocationChange.js +31 -0
  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 -27
  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 -13
  200. package/src/components/Collapsible/index.tsx +263 -0
  201. package/src/components/Details/index.tsx +109 -0
  202. package/src/components/Details/styles.module.css +62 -0
  203. package/src/contexts/announcementBar.tsx +119 -0
  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 +55 -23
  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 +59 -26
  245. package/src/utils/tagsUtils.ts +50 -0
  246. package/src/utils/tocUtils.ts +119 -0
  247. package/src/utils/useAlternatePageUtils.ts +28 -7
  248. package/src/utils/useLocalPathname.ts +22 -0
  249. package/src/utils/useLocationChange.ts +41 -0
  250. package/src/utils/usePluralForm.ts +53 -39
  251. package/src/utils/useThemeConfig.ts +55 -29
  252. package/lib/.tsbuildinfo +0 -4115
  253. package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.d.ts +0 -21
  254. package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.js +0 -94
  255. package/lib/utils/docsPreferredVersion/DocsPreferredVersionStorage.d.ts +0 -13
  256. package/lib/utils/docsPreferredVersion/DocsPreferredVersionStorage.js +0 -20
  257. package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.d.ts +0 -5
  258. package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.js +0 -41
  259. package/lib/utils/pathUtils.js +0 -13
  260. package/lib/utils/useChangeRoute.js +0 -18
  261. package/src/utils/__tests__/codeBlockUtils.test.ts +0 -54
  262. package/src/utils/__tests__/pathUtils.test.ts +0 -32
  263. package/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx +0 -165
  264. package/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts +0 -34
  265. package/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts +0 -66
  266. package/src/utils/docsUtils.ts +0 -11
  267. package/src/utils/pathUtils.ts +0 -17
  268. package/src/utils/useChangeRoute.ts +0 -21
  269. package/tsconfig.json +0 -10
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import React, {
9
+ useState,
10
+ useEffect,
11
+ useRef,
12
+ useCallback,
13
+ useLayoutEffect,
14
+ type RefObject,
15
+ type Dispatch,
16
+ type SetStateAction,
17
+ type ReactNode,
18
+ } from 'react';
19
+ import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
20
+
21
+ const DefaultAnimationEasing = 'ease-in-out';
22
+
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
+ }): {
32
+ collapsed: boolean;
33
+ setCollapsed: Dispatch<SetStateAction<boolean>>;
34
+ toggleCollapsed: () => void;
35
+ } {
36
+ const [collapsed, setCollapsed] = useState(initialState ?? false);
37
+
38
+ const toggleCollapsed = useCallback(() => {
39
+ setCollapsed((expanded) => !expanded);
40
+ }, []);
41
+
42
+ return {
43
+ collapsed,
44
+ setCollapsed,
45
+ toggleCollapsed,
46
+ };
47
+ }
48
+
49
+ const CollapsedStyles = {
50
+ display: 'none',
51
+ overflow: 'hidden',
52
+ height: '0px',
53
+ } as const;
54
+
55
+ const ExpandedStyles = {
56
+ display: 'block',
57
+ overflow: 'visible',
58
+ height: 'auto',
59
+ } as const;
60
+
61
+ function applyCollapsedStyle(el: HTMLElement, collapsed: boolean) {
62
+ const collapsedStyles = collapsed ? CollapsedStyles : ExpandedStyles;
63
+ el.style.display = collapsedStyles.display;
64
+ el.style.overflow = collapsedStyles.overflow;
65
+ el.style.height = collapsedStyles.height;
66
+ }
67
+
68
+ /*
69
+ Lex111: Dynamic transition duration is used in Material design, this technique
70
+ is good for a large number of items.
71
+ https://material.io/archive/guidelines/motion/duration-easing.html#duration-easing-dynamic-durations
72
+ https://github.com/mui-org/material-ui/blob/e724d98eba018e55e1a684236a2037e24bcf050c/packages/material-ui/src/styles/createTransitions.js#L40-L43
73
+ */
74
+ function getAutoHeightDuration(height: number) {
75
+ const constant = height / 36;
76
+ return Math.round((4 + 15 * constant ** 0.25 + constant / 5) * 10);
77
+ }
78
+
79
+ type CollapsibleAnimationConfig = {
80
+ duration?: number;
81
+ easing?: string;
82
+ };
83
+
84
+ function useCollapseAnimation({
85
+ collapsibleRef,
86
+ collapsed,
87
+ animation,
88
+ }: {
89
+ collapsibleRef: RefObject<HTMLElement>;
90
+ collapsed: boolean;
91
+ animation?: CollapsibleAnimationConfig;
92
+ }) {
93
+ const mounted = useRef(false);
94
+
95
+ useEffect(() => {
96
+ const el = collapsibleRef.current!;
97
+
98
+ function getTransitionStyles() {
99
+ const height = el.scrollHeight;
100
+ const duration = animation?.duration ?? getAutoHeightDuration(height);
101
+ const easing = animation?.easing ?? DefaultAnimationEasing;
102
+ return {
103
+ transition: `height ${duration}ms ${easing}`,
104
+ height: `${height}px`,
105
+ };
106
+ }
107
+
108
+ function applyTransitionStyles() {
109
+ const transitionStyles = getTransitionStyles();
110
+ el.style.transition = transitionStyles.transition;
111
+ el.style.height = transitionStyles.height;
112
+ }
113
+
114
+ // On mount, we just apply styles, no animated transition
115
+ if (!mounted.current) {
116
+ applyCollapsedStyle(el, collapsed);
117
+ mounted.current = true;
118
+ return undefined;
119
+ }
120
+
121
+ el.style.willChange = 'height';
122
+
123
+ function startAnimation() {
124
+ const animationFrame = requestAnimationFrame(() => {
125
+ // When collapsing
126
+ if (collapsed) {
127
+ applyTransitionStyles();
128
+
129
+ requestAnimationFrame(() => {
130
+ el.style.height = CollapsedStyles.height;
131
+ el.style.overflow = CollapsedStyles.overflow;
132
+ });
133
+ }
134
+ // When expanding
135
+ else {
136
+ el.style.display = 'block';
137
+ requestAnimationFrame(() => {
138
+ applyTransitionStyles();
139
+ });
140
+ }
141
+ });
142
+
143
+ return () => cancelAnimationFrame(animationFrame);
144
+ }
145
+
146
+ return startAnimation();
147
+ }, [collapsibleRef, collapsed, animation]);
148
+ }
149
+
150
+ type CollapsibleElementType = React.ElementType<
151
+ Pick<React.HTMLAttributes<unknown>, 'className' | 'onTransitionEnd' | 'style'>
152
+ >;
153
+
154
+ /**
155
+ * Prevent hydration layout shift before animations are handled imperatively
156
+ * with JS
157
+ */
158
+ function getSSRStyle(collapsed: boolean) {
159
+ if (ExecutionEnvironment.canUseDOM) {
160
+ return undefined;
161
+ }
162
+ return collapsed ? CollapsedStyles : ExpandedStyles;
163
+ }
164
+
165
+ type CollapsibleBaseProps = {
166
+ /** The actual DOM element to be used in the markup. */
167
+ as?: CollapsibleElementType;
168
+ /** Initial collapsed state. */
169
+ collapsed: boolean;
170
+ children: ReactNode;
171
+ /** Configuration of animation, like `duration` and `easing` */
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
+ */
179
+ onCollapseTransitionEnd?: (collapsed: boolean) => void;
180
+ /** Class name for the underlying DOM element. */
181
+ className?: string;
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
+ */
187
+ disableSSRStyle?: boolean;
188
+ };
189
+
190
+ function CollapsibleBase({
191
+ as: As = 'div',
192
+ collapsed,
193
+ children,
194
+ animation,
195
+ onCollapseTransitionEnd,
196
+ className,
197
+ disableSSRStyle,
198
+ }: CollapsibleBaseProps) {
199
+ const collapsibleRef = useRef<HTMLElement>(null);
200
+
201
+ useCollapseAnimation({collapsibleRef, collapsed, animation});
202
+
203
+ return (
204
+ <As
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
208
+ style={disableSSRStyle ? undefined : getSSRStyle(collapsed)}
209
+ onTransitionEnd={(e: React.TransitionEvent) => {
210
+ if (e.propertyName !== 'height') {
211
+ return;
212
+ }
213
+
214
+ applyCollapsedStyle(collapsibleRef.current!, collapsed);
215
+ onCollapseTransitionEnd?.(collapsed);
216
+ }}
217
+ className={className}>
218
+ {children}
219
+ </As>
220
+ );
221
+ }
222
+
223
+ function CollapsibleLazy({collapsed, ...props}: CollapsibleBaseProps) {
224
+ const [mounted, setMounted] = useState(!collapsed);
225
+ // Updated in effect so that first expansion transition can work
226
+ const [lazyCollapsed, setLazyCollapsed] = useState(collapsed);
227
+
228
+ useLayoutEffect(() => {
229
+ if (!collapsed) {
230
+ setMounted(true);
231
+ }
232
+ }, [collapsed]);
233
+
234
+ useLayoutEffect(() => {
235
+ if (mounted) {
236
+ setLazyCollapsed(collapsed);
237
+ }
238
+ }, [mounted, collapsed]);
239
+
240
+ return mounted ? (
241
+ <CollapsibleBase {...props} collapsed={lazyCollapsed} />
242
+ ) : null;
243
+ }
244
+
245
+ type CollapsibleProps = CollapsibleBaseProps & {
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
+ */
252
+ lazy: boolean;
253
+ };
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
+ */
260
+ export function Collapsible({lazy, ...props}: CollapsibleProps): JSX.Element {
261
+ const Comp = lazy ? CollapsibleLazy : CollapsibleBase;
262
+ return <Comp {...props} />;
263
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import React, {
9
+ useRef,
10
+ useState,
11
+ type ComponentProps,
12
+ type ReactElement,
13
+ } from 'react';
14
+ import clsx from 'clsx';
15
+ import useIsBrowser from '@docusaurus/useIsBrowser';
16
+ import {useCollapsible, Collapsible} from '../Collapsible';
17
+ import styles from './styles.module.css';
18
+
19
+ function isInSummary(node: HTMLElement | null): boolean {
20
+ if (!node) {
21
+ return false;
22
+ }
23
+ return node.tagName === 'SUMMARY' || isInSummary(node.parentElement);
24
+ }
25
+
26
+ function hasParent(node: HTMLElement | null, parent: HTMLElement): boolean {
27
+ if (!node) {
28
+ return false;
29
+ }
30
+ return node === parent || hasParent(node.parentElement, parent);
31
+ }
32
+
33
+ export type DetailsProps = {
34
+ /** Summary is provided as props, including the wrapping `<summary>` tag */
35
+ summary?: ReactElement;
36
+ } & ComponentProps<'details'>;
37
+
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();
48
+ const detailsRef = useRef<HTMLDetailsElement>(null);
49
+
50
+ const {collapsed, setCollapsed} = useCollapsible({
51
+ initialState: !props.open,
52
+ });
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
55
+ const [open, setOpen] = useState(props.open);
56
+
57
+ return (
58
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
59
+ <details
60
+ {...props}
61
+ ref={detailsRef}
62
+ open={open}
63
+ data-collapsed={collapsed}
64
+ className={clsx(
65
+ styles.details,
66
+ isBrowser && styles.isBrowser,
67
+ props.className,
68
+ )}
69
+ onMouseDown={(e) => {
70
+ const target = e.target as HTMLElement;
71
+ // Prevent a double-click to highlight summary text
72
+ if (isInSummary(target) && e.detail > 1) {
73
+ e.preventDefault();
74
+ }
75
+ }}
76
+ onClick={(e) => {
77
+ e.stopPropagation(); // For isolation of multiple nested details/summary
78
+ const target = e.target as HTMLElement;
79
+ const shouldToggle =
80
+ isInSummary(target) && hasParent(target, detailsRef.current!);
81
+ if (!shouldToggle) {
82
+ return;
83
+ }
84
+ e.preventDefault();
85
+ if (collapsed) {
86
+ setCollapsed(false);
87
+ setOpen(true);
88
+ } else {
89
+ setCollapsed(true);
90
+ // Don't do this, it breaks close animation!
91
+ // setOpen(false);
92
+ }
93
+ }}>
94
+ {/* eslint-disable-next-line @docusaurus/no-untranslated-text */}
95
+ {summary ?? <summary>Details</summary>}
96
+
97
+ <Collapsible
98
+ lazy={false} // Content might matter for SEO in this case
99
+ collapsed={collapsed}
100
+ disableSSRStyle // Allows component to work fine even with JS disabled!
101
+ onCollapseTransitionEnd={(newCollapsed) => {
102
+ setCollapsed(newCollapsed);
103
+ setOpen(!newCollapsed);
104
+ }}>
105
+ <div className={styles.collapsibleContent}>{children}</div>
106
+ </Collapsible>
107
+ </details>
108
+ );
109
+ }
@@ -0,0 +1,62 @@
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
+ /*
9
+ CSS variables, meant to be overridden by final theme
10
+ */
11
+ .details {
12
+ --docusaurus-details-summary-arrow-size: 0.38rem;
13
+ --docusaurus-details-transition: transform 200ms ease;
14
+ --docusaurus-details-decoration-color: grey;
15
+ }
16
+
17
+ .details > summary {
18
+ position: relative;
19
+ cursor: pointer;
20
+ list-style: none;
21
+ padding-left: 1rem;
22
+ }
23
+
24
+ /* TODO: deprecation, need to remove this after Safari will support `::marker` */
25
+ .details > summary::-webkit-details-marker {
26
+ display: none;
27
+ }
28
+
29
+ .details > summary::before {
30
+ position: absolute;
31
+ top: 0.45rem;
32
+ left: 0;
33
+
34
+ /* CSS-only Arrow */
35
+ content: '';
36
+ border-width: var(--docusaurus-details-summary-arrow-size);
37
+ border-style: solid;
38
+ border-color: transparent transparent transparent
39
+ var(--docusaurus-details-decoration-color);
40
+
41
+ /* Arrow rotation anim */
42
+ transform: rotate(0deg);
43
+ transition: var(--docusaurus-details-transition);
44
+ transform-origin: calc(var(--docusaurus-details-summary-arrow-size) / 2) 50%;
45
+ }
46
+
47
+ /* When JS disabled/failed to load: we use the open property for arrow animation: */
48
+ .details[open]:not(.isBrowser) > summary::before,
49
+ /* When JS works: we use the data-attribute for arrow animation */
50
+ .details[data-collapsed='false'].isBrowser > summary::before {
51
+ transform: rotate(90deg);
52
+ }
53
+
54
+ .collapsibleContent {
55
+ margin-top: 1rem;
56
+ border-top: 1px solid var(--docusaurus-details-decoration-color);
57
+ padding-top: 1rem;
58
+ }
59
+
60
+ .collapsibleContent > *:last-child {
61
+ margin-bottom: 0;
62
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import React, {
9
+ useState,
10
+ useEffect,
11
+ useCallback,
12
+ useMemo,
13
+ useContext,
14
+ type ReactNode,
15
+ } from 'react';
16
+ import useIsBrowser from '@docusaurus/useIsBrowser';
17
+ import {createStorageSlot} from '../utils/storageUtils';
18
+ import {ReactContextError} from '../utils/reactUtils';
19
+ import {useThemeConfig} from '../utils/useThemeConfig';
20
+
21
+ export const AnnouncementBarDismissStorageKey =
22
+ 'docusaurus.announcement.dismiss';
23
+ const AnnouncementBarIdStorageKey = 'docusaurus.announcement.id';
24
+
25
+ const AnnouncementBarDismissStorage = createStorageSlot(
26
+ AnnouncementBarDismissStorageKey,
27
+ );
28
+ const IdStorage = createStorageSlot(AnnouncementBarIdStorageKey);
29
+
30
+ const isDismissedInStorage = () =>
31
+ AnnouncementBarDismissStorage.get() === 'true';
32
+ const setDismissedInStorage = (bool: boolean) =>
33
+ AnnouncementBarDismissStorage.set(String(bool));
34
+
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
+ */
41
+ readonly close: () => void;
42
+ };
43
+
44
+ const Context = React.createContext<ContextValue | null>(null);
45
+
46
+ function useContextValue(): ContextValue {
47
+ const {announcementBar} = useThemeConfig();
48
+ const isBrowser = useIsBrowser();
49
+
50
+ const [isClosed, setClosed] = useState(() =>
51
+ isBrowser
52
+ ? // On client navigation: init with local storage value
53
+ isDismissedInStorage()
54
+ : // On server/hydration: always visible to prevent layout shifts (will be hidden with css if needed)
55
+ false,
56
+ );
57
+ // Update state after hydration
58
+ useEffect(() => {
59
+ setClosed(isDismissedInStorage());
60
+ }, []);
61
+
62
+ const handleClose = useCallback(() => {
63
+ setDismissedInStorage(true);
64
+ setClosed(true);
65
+ }, []);
66
+
67
+ useEffect(() => {
68
+ if (!announcementBar) {
69
+ return;
70
+ }
71
+ const {id} = announcementBar;
72
+
73
+ let viewedId = IdStorage.get();
74
+
75
+ // Retrocompatibility due to spelling mistake of default id
76
+ // see https://github.com/facebook/docusaurus/issues/3338
77
+ // cSpell:ignore annoucement
78
+ if (viewedId === 'annoucement-bar') {
79
+ viewedId = 'announcement-bar';
80
+ }
81
+
82
+ const isNewAnnouncement = id !== viewedId;
83
+
84
+ IdStorage.set(id);
85
+
86
+ if (isNewAnnouncement) {
87
+ setDismissedInStorage(false);
88
+ }
89
+
90
+ if (isNewAnnouncement || !isDismissedInStorage()) {
91
+ setClosed(false);
92
+ }
93
+ }, [announcementBar]);
94
+
95
+ return useMemo(
96
+ () => ({
97
+ isActive: !!announcementBar && !isClosed,
98
+ close: handleClose,
99
+ }),
100
+ [announcementBar, isClosed, handleClose],
101
+ );
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);
115
+ if (!api) {
116
+ throw new ReactContextError('AnnouncementBarProvider');
117
+ }
118
+ return api;
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
+ }