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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/lib/getSwizzleConfig.js +113 -2
  2. package/lib/index.js +7 -12
  3. package/lib/theme-classic.d.ts +286 -60
  4. package/lib/translations.js +12 -2
  5. package/lib/validateThemeConfig.js +1 -1
  6. package/lib-next/theme/BackToTopButton/index.js +1 -3
  7. package/lib-next/theme/BlogArchivePage/index.js +14 -10
  8. package/lib-next/theme/BlogListPage/index.js +34 -13
  9. package/lib-next/theme/BlogPostItem/index.js +6 -6
  10. package/lib-next/theme/BlogPostPage/index.js +56 -45
  11. package/lib-next/theme/BlogTagsListPage/index.js +16 -12
  12. package/lib-next/theme/BlogTagsPostsPage/index.js +40 -33
  13. package/lib-next/theme/CodeBlock/CopyButton/index.js +60 -0
  14. package/lib-next/theme/CodeBlock/CopyButton/styles.module.css +66 -0
  15. package/lib-next/theme/CodeBlock/index.js +4 -36
  16. package/lib-next/theme/CodeBlock/styles.module.css +2 -22
  17. package/lib-next/theme/ColorModeToggle/index.js +36 -57
  18. package/lib-next/theme/ColorModeToggle/styles.module.css +8 -24
  19. package/lib-next/theme/DocBreadcrumbs/index.js +28 -11
  20. package/lib-next/theme/DocBreadcrumbs/styles.module.css +2 -17
  21. package/lib-next/theme/DocCard/index.js +17 -15
  22. package/lib-next/theme/DocCard/styles.module.css +8 -17
  23. package/lib-next/theme/DocCardList/index.js +15 -3
  24. package/lib-next/theme/DocCategoryGeneratedIndexPage/index.js +27 -6
  25. package/lib-next/theme/DocItem/index.js +84 -66
  26. package/lib-next/theme/DocPage/index.js +88 -89
  27. package/lib-next/theme/DocPage/styles.module.css +0 -4
  28. package/lib-next/theme/DocSidebar/Desktop/CollapseButton/index.js +34 -0
  29. package/lib-next/theme/DocSidebar/Desktop/CollapseButton/styles.module.css +44 -0
  30. package/lib-next/theme/DocSidebar/Desktop/Content/index.js +46 -0
  31. package/lib-next/theme/DocSidebar/Desktop/Content/styles.module.css +17 -0
  32. package/lib-next/theme/DocSidebar/Desktop/index.js +34 -0
  33. package/lib-next/theme/DocSidebar/Desktop/styles.module.css +50 -0
  34. package/lib-next/theme/DocSidebar/Mobile/index.js +49 -0
  35. package/lib-next/theme/DocSidebar/index.js +6 -113
  36. package/lib-next/theme/DocSidebarItem/index.js +14 -13
  37. package/lib-next/theme/DocSidebarItem/styles.module.css +4 -0
  38. package/lib-next/theme/DocTagDocListPage/index.js +38 -31
  39. package/lib-next/theme/DocTagsListPage/index.js +21 -16
  40. package/lib-next/theme/Footer/Copyright/index.js +18 -0
  41. package/lib-next/theme/Footer/Layout/index.js +26 -0
  42. package/lib-next/theme/Footer/LinkItem/index.js +33 -0
  43. package/lib-next/theme/Footer/Links/MultiColumn/index.js +47 -0
  44. package/lib-next/theme/Footer/Links/Simple/index.js +41 -0
  45. package/lib-next/theme/Footer/Links/index.js +17 -0
  46. package/lib-next/theme/Footer/Logo/index.js +38 -0
  47. package/lib-next/theme/Footer/{styles.module.css → Logo/styles.module.css} +0 -0
  48. package/lib-next/theme/Footer/index.js +11 -163
  49. package/lib-next/theme/Heading/index.js +6 -4
  50. package/lib-next/theme/IconExternalLink/styles.module.css +0 -2
  51. package/lib-next/theme/Layout/index.js +15 -10
  52. package/lib-next/theme/LayoutProviders/index.js +5 -4
  53. package/lib-next/theme/MDXComponents/A.js +11 -0
  54. package/lib-next/theme/MDXComponents/Code.js +28 -0
  55. package/lib-next/theme/MDXComponents/Details.js +20 -0
  56. package/lib-next/theme/MDXComponents/Head.js +26 -0
  57. package/lib-next/theme/MDXComponents/Heading.js +11 -0
  58. package/lib-next/theme/MDXComponents/Img.js +24 -0
  59. package/lib-next/theme/MDXComponents/Img.module.css +10 -0
  60. package/lib-next/theme/MDXComponents/Pre.js +18 -0
  61. package/lib-next/theme/MDXComponents/Ul.js +23 -0
  62. package/{src/theme/MDXComponents/styles.css → lib-next/theme/MDXComponents/Ul.module.css} +1 -5
  63. package/lib-next/theme/MDXComponents/index.js +22 -71
  64. package/lib-next/theme/MDXContent/index.js +12 -0
  65. package/lib-next/theme/MDXPage/index.js +33 -28
  66. package/lib-next/theme/Navbar/ColorModeToggle/index.js +25 -0
  67. package/lib-next/theme/Navbar/Content/index.js +70 -0
  68. package/lib-next/theme/Navbar/Content/styles.module.css +15 -0
  69. package/lib-next/theme/Navbar/Layout/index.js +54 -0
  70. package/{src/theme/Navbar → lib-next/theme/Navbar/Layout}/styles.module.css +0 -13
  71. package/lib-next/theme/Navbar/Logo/index.js +17 -0
  72. package/lib-next/theme/Navbar/MobileSidebar/Header/index.js +33 -0
  73. package/lib-next/theme/Navbar/MobileSidebar/Layout/index.js +28 -0
  74. package/lib-next/theme/Navbar/MobileSidebar/PrimaryMenu/index.js +33 -0
  75. package/lib-next/theme/Navbar/MobileSidebar/SecondaryMenu/index.js +36 -0
  76. package/lib-next/theme/Navbar/MobileSidebar/Toggle/index.js +23 -0
  77. package/lib-next/theme/Navbar/MobileSidebar/index.js +31 -0
  78. package/lib-next/theme/Navbar/index.js +6 -271
  79. package/lib-next/theme/NavbarItem/DefaultNavbarItem.js +2 -6
  80. package/lib-next/theme/NavbarItem/DropdownNavbarItem.js +10 -2
  81. package/lib-next/theme/NavbarItem/NavbarNavLink.js +8 -12
  82. package/lib-next/theme/NotFound.js +38 -33
  83. package/lib-next/theme/{LayoutHead → SiteMetadata}/index.js +11 -26
  84. package/lib-next/theme/TOCCollapsible/index.js +1 -3
  85. package/lib-next/theme/Tabs/__tests__/index.test.js +5 -5
  86. package/lib-next/theme/Tabs/index.js +2 -2
  87. package/lib-next/theme/Tag/index.js +4 -4
  88. package/lib-next/theme/ThemedImage/index.js +3 -3
  89. package/package.json +17 -17
  90. package/src/getSwizzleConfig.ts +122 -1
  91. package/src/index.ts +10 -12
  92. package/src/theme/BackToTopButton/index.tsx +1 -3
  93. package/src/theme/BlogArchivePage/index.tsx +18 -17
  94. package/src/theme/BlogLayout/index.tsx +1 -1
  95. package/src/theme/BlogListPage/index.tsx +32 -13
  96. package/src/theme/BlogPostItem/index.tsx +6 -6
  97. package/src/theme/BlogPostPage/index.tsx +55 -48
  98. package/src/theme/BlogTagsListPage/index.tsx +16 -12
  99. package/src/theme/BlogTagsPostsPage/index.tsx +39 -32
  100. package/src/theme/CodeBlock/CopyButton/index.tsx +66 -0
  101. package/src/theme/CodeBlock/CopyButton/styles.module.css +66 -0
  102. package/src/theme/CodeBlock/index.tsx +6 -38
  103. package/src/theme/CodeBlock/styles.module.css +2 -22
  104. package/src/theme/ColorModeToggle/index.tsx +36 -61
  105. package/src/theme/ColorModeToggle/styles.module.css +8 -24
  106. package/src/theme/DocBreadcrumbs/index.tsx +29 -10
  107. package/src/theme/DocBreadcrumbs/styles.module.css +2 -17
  108. package/src/theme/DocCard/index.tsx +24 -17
  109. package/src/theme/DocCard/styles.module.css +8 -17
  110. package/src/theme/DocCardList/index.tsx +14 -3
  111. package/src/theme/DocCategoryGeneratedIndexPage/index.tsx +31 -4
  112. package/src/theme/DocItem/index.tsx +71 -55
  113. package/src/theme/DocPage/index.tsx +89 -90
  114. package/src/theme/DocPage/styles.module.css +0 -4
  115. package/src/theme/DocSidebar/Desktop/CollapseButton/index.tsx +38 -0
  116. package/src/theme/DocSidebar/Desktop/CollapseButton/styles.module.css +44 -0
  117. package/src/theme/DocSidebar/Desktop/Content/index.tsx +55 -0
  118. package/src/theme/DocSidebar/Desktop/Content/styles.module.css +17 -0
  119. package/src/theme/DocSidebar/Desktop/index.tsx +38 -0
  120. package/src/theme/DocSidebar/Desktop/styles.module.css +50 -0
  121. package/src/theme/DocSidebar/Mobile/index.tsx +54 -0
  122. package/src/theme/DocSidebar/index.tsx +6 -121
  123. package/src/theme/DocSidebarItem/index.tsx +15 -16
  124. package/src/theme/DocSidebarItem/styles.module.css +4 -0
  125. package/src/theme/DocTagDocListPage/index.tsx +38 -30
  126. package/src/theme/DocTagsListPage/index.tsx +21 -16
  127. package/src/theme/DocVersionBanner/index.tsx +3 -4
  128. package/src/theme/Footer/Copyright/index.tsx +20 -0
  129. package/src/theme/Footer/Layout/index.tsx +34 -0
  130. package/src/theme/Footer/LinkItem/index.tsx +36 -0
  131. package/src/theme/Footer/Links/MultiColumn/index.tsx +51 -0
  132. package/src/theme/Footer/Links/Simple/index.tsx +42 -0
  133. package/src/theme/Footer/Links/index.tsx +21 -0
  134. package/src/theme/Footer/Logo/index.tsx +41 -0
  135. package/src/theme/Footer/{styles.module.css → Logo/styles.module.css} +0 -0
  136. package/src/theme/Footer/index.tsx +12 -186
  137. package/src/theme/Heading/index.tsx +6 -4
  138. package/src/theme/IconExternalLink/styles.module.css +0 -2
  139. package/src/theme/Layout/index.tsx +15 -10
  140. package/src/theme/LayoutProviders/index.tsx +5 -4
  141. package/src/theme/MDXComponents/A.tsx +14 -0
  142. package/src/theme/MDXComponents/Code.tsx +37 -0
  143. package/src/theme/MDXComponents/Details.tsx +26 -0
  144. package/src/theme/MDXComponents/Head.tsx +29 -0
  145. package/src/theme/MDXComponents/Heading.tsx +14 -0
  146. package/src/theme/MDXComponents/Img.module.css +10 -0
  147. package/src/theme/MDXComponents/Img.tsx +26 -0
  148. package/src/theme/MDXComponents/Pre.tsx +22 -0
  149. package/{lib-next/theme/MDXComponents/styles.css → src/theme/MDXComponents/Ul.module.css} +1 -5
  150. package/src/theme/MDXComponents/Ul.tsx +28 -0
  151. package/src/theme/MDXComponents/index.tsx +23 -80
  152. package/src/theme/MDXContent/index.tsx +15 -0
  153. package/src/theme/MDXPage/index.tsx +33 -28
  154. package/src/theme/Navbar/ColorModeToggle/index.tsx +30 -0
  155. package/src/theme/Navbar/Content/index.tsx +81 -0
  156. package/src/theme/Navbar/Content/styles.module.css +15 -0
  157. package/src/theme/Navbar/Layout/index.tsx +57 -0
  158. package/{lib-next/theme/Navbar → src/theme/Navbar/Layout}/styles.module.css +0 -13
  159. package/src/theme/Navbar/Logo/index.tsx +19 -0
  160. package/src/theme/Navbar/MobileSidebar/Header/index.tsx +34 -0
  161. package/src/theme/Navbar/MobileSidebar/Layout/index.tsx +31 -0
  162. package/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx +38 -0
  163. package/src/theme/Navbar/MobileSidebar/SecondaryMenu/index.tsx +38 -0
  164. package/src/theme/Navbar/MobileSidebar/Toggle/index.tsx +25 -0
  165. package/src/theme/Navbar/MobileSidebar/index.tsx +33 -0
  166. package/src/theme/Navbar/index.tsx +6 -286
  167. package/src/theme/NavbarItem/DefaultNavbarItem.tsx +2 -2
  168. package/src/theme/NavbarItem/DropdownNavbarItem.tsx +11 -2
  169. package/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx +1 -1
  170. package/src/theme/NavbarItem/NavbarNavLink.tsx +3 -7
  171. package/src/theme/NavbarItem/index.tsx +3 -4
  172. package/src/theme/NotFound.tsx +38 -33
  173. package/src/theme/{LayoutHead → SiteMetadata}/index.tsx +11 -25
  174. package/src/theme/TOCCollapsible/index.tsx +1 -3
  175. package/src/theme/Tabs/index.tsx +5 -6
  176. package/src/theme/Tag/index.tsx +4 -4
  177. package/src/theme/ThemedImage/index.tsx +4 -3
  178. package/src/theme-classic.d.ts +286 -60
  179. package/src/translations.ts +12 -6
  180. package/src/validateThemeConfig.ts +6 -6
  181. package/lib-next/theme/DocSidebar/styles.module.css +0 -107
  182. package/lib-next/theme/Seo/index.js +0 -40
  183. package/src/theme/DocSidebar/styles.module.css +0 -107
  184. package/src/theme/Seo/index.tsx +0 -49
@@ -5,294 +5,14 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import React, {useCallback, useState, useEffect} from 'react';
9
- import clsx from 'clsx';
10
- import Translate from '@docusaurus/Translate';
11
- import SearchBar from '@theme/SearchBar';
12
- import ColorModeToggle from '@theme/ColorModeToggle';
13
- import {
14
- useThemeConfig,
15
- useMobileSecondaryMenuRenderer,
16
- usePrevious,
17
- useHistoryPopHandler,
18
- useHideableNavbar,
19
- useLockBodyScroll,
20
- useWindowSize,
21
- useColorMode,
22
- } from '@docusaurus/theme-common';
23
- import {useActivePlugin} from '@docusaurus/plugin-content-docs/client';
24
- import NavbarItem, {type Props as NavbarItemConfig} from '@theme/NavbarItem';
25
- import Logo from '@theme/Logo';
26
- import IconMenu from '@theme/IconMenu';
27
- import IconClose from '@theme/IconClose';
28
-
29
- import styles from './styles.module.css';
30
-
31
- // retrocompatible with v1
32
- const DefaultNavItemPosition = 'right';
33
-
34
- function useNavbarItems() {
35
- // TODO temporary casting until ThemeConfig type is improved
36
- return useThemeConfig().navbar.items as NavbarItemConfig[];
37
- }
38
-
39
- // If split links by left/right
40
- // if position is unspecified, fallback to right (as v1)
41
- function splitNavItemsByPosition(items: NavbarItemConfig[]) {
42
- const leftItems = items.filter(
43
- (item) => (item.position ?? DefaultNavItemPosition) === 'left',
44
- );
45
- const rightItems = items.filter(
46
- (item) => (item.position ?? DefaultNavItemPosition) === 'right',
47
- );
48
- return {
49
- leftItems,
50
- rightItems,
51
- };
52
- }
53
-
54
- function useMobileSidebar() {
55
- const windowSize = useWindowSize();
56
-
57
- // Mobile sidebar not visible on hydration: can avoid SSR rendering
58
- const shouldRender = windowSize === 'mobile'; // || windowSize === 'ssr';
59
-
60
- const [shown, setShown] = useState(false);
61
-
62
- // Close mobile sidebar on navigation pop
63
- // Most likely firing when using the Android back button (but not only)
64
- useHistoryPopHandler(() => {
65
- if (shown) {
66
- setShown(false);
67
- // Should we prevent the navigation here?
68
- // See https://github.com/facebook/docusaurus/pull/5462#issuecomment-911699846
69
- return false; // prevent pop navigation
70
- }
71
- return undefined;
72
- });
73
-
74
- const toggle = useCallback(() => {
75
- setShown((s) => !s);
76
- }, []);
77
-
78
- useEffect(() => {
79
- if (windowSize === 'desktop') {
80
- setShown(false);
81
- }
82
- }, [windowSize]);
83
-
84
- return {shouldRender, toggle, shown};
85
- }
86
-
87
- function useColorModeToggle() {
88
- const {
89
- colorMode: {disableSwitch},
90
- } = useThemeConfig();
91
- const {isDarkTheme, setLightTheme, setDarkTheme} = useColorMode();
92
- const toggle = useCallback(
93
- (e) => (e.target.checked ? setDarkTheme() : setLightTheme()),
94
- [setLightTheme, setDarkTheme],
95
- );
96
- return {isDarkTheme, toggle, disabled: disableSwitch};
97
- }
98
-
99
- function useSecondaryMenu({
100
- sidebarShown,
101
- toggleSidebar,
102
- }: NavbarMobileSidebarProps) {
103
- const content = useMobileSecondaryMenuRenderer()?.({
104
- toggleSidebar,
105
- });
106
- const previousContent = usePrevious(content);
107
-
108
- const [shown, setShown] = useState<boolean>(
109
- () =>
110
- // /!\ content is set with useEffect,
111
- // so it's not available on mount anyway
112
- // "return !!content" => always returns false
113
- false,
114
- );
115
-
116
- // When content is become available for the first time (set in useEffect)
117
- // we set this content to be shown!
118
- useEffect(() => {
119
- const contentBecameAvailable = content && !previousContent;
120
- if (contentBecameAvailable) {
121
- setShown(true);
122
- }
123
- }, [content, previousContent]);
124
-
125
- const hasContent = !!content;
126
-
127
- // On sidebar close, secondary menu is set to be shown on next re-opening
128
- // (if any secondary menu content available)
129
- useEffect(() => {
130
- if (!hasContent) {
131
- setShown(false);
132
- return;
133
- }
134
- if (!sidebarShown) {
135
- setShown(true);
136
- }
137
- }, [sidebarShown, hasContent]);
138
-
139
- const hide = useCallback(() => {
140
- setShown(false);
141
- }, []);
142
-
143
- return {shown, hide, content};
144
- }
145
-
146
- type NavbarMobileSidebarProps = {
147
- sidebarShown: boolean;
148
- toggleSidebar: () => void;
149
- };
150
-
151
- function NavbarMobileSidebar({
152
- sidebarShown,
153
- toggleSidebar,
154
- }: NavbarMobileSidebarProps) {
155
- useLockBodyScroll(sidebarShown);
156
- const items = useNavbarItems();
157
-
158
- const colorModeToggle = useColorModeToggle();
159
-
160
- const secondaryMenu = useSecondaryMenu({
161
- sidebarShown,
162
- toggleSidebar,
163
- });
164
-
165
- return (
166
- <div className="navbar-sidebar">
167
- <div className="navbar-sidebar__brand">
168
- <Logo
169
- className="navbar__brand"
170
- imageClassName="navbar__logo"
171
- titleClassName="navbar__title"
172
- />
173
- {!colorModeToggle.disabled && (
174
- <ColorModeToggle
175
- className={styles.navbarSidebarToggle}
176
- checked={colorModeToggle.isDarkTheme}
177
- onChange={colorModeToggle.toggle}
178
- />
179
- )}
180
- <button
181
- type="button"
182
- className="clean-btn navbar-sidebar__close"
183
- onClick={toggleSidebar}>
184
- <IconClose
185
- color="var(--ifm-color-emphasis-600)"
186
- className={styles.navbarSidebarCloseSvg}
187
- />
188
- </button>
189
- </div>
190
-
191
- <div
192
- className={clsx('navbar-sidebar__items', {
193
- 'navbar-sidebar__items--show-secondary': secondaryMenu.shown,
194
- })}>
195
- <div className="navbar-sidebar__item menu">
196
- <ul className="menu__list">
197
- {items.map((item, i) => (
198
- <NavbarItem mobile {...item} onClick={toggleSidebar} key={i} />
199
- ))}
200
- </ul>
201
- </div>
202
-
203
- <div className="navbar-sidebar__item menu">
204
- {items.length > 0 && (
205
- <button
206
- type="button"
207
- className="clean-btn navbar-sidebar__back"
208
- onClick={secondaryMenu.hide}>
209
- <Translate
210
- id="theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel"
211
- description="The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)">
212
- ← Back to main menu
213
- </Translate>
214
- </button>
215
- )}
216
- {secondaryMenu.content}
217
- </div>
218
- </div>
219
- </div>
220
- );
221
- }
8
+ import React from 'react';
9
+ import NavbarLayout from '@theme/Navbar/Layout';
10
+ import NavbarContent from '@theme/Navbar/Content';
222
11
 
223
12
  export default function Navbar(): JSX.Element {
224
- const {
225
- navbar: {hideOnScroll, style},
226
- } = useThemeConfig();
227
-
228
- const mobileSidebar = useMobileSidebar();
229
- const colorModeToggle = useColorModeToggle();
230
- const activeDocPlugin = useActivePlugin();
231
- const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll);
232
-
233
- const items = useNavbarItems();
234
- const hasSearchNavbarItem = items.some((item) => item.type === 'search');
235
- const {leftItems, rightItems} = splitNavItemsByPosition(items);
236
-
237
13
  return (
238
- <nav
239
- ref={navbarRef}
240
- className={clsx('navbar', 'navbar--fixed-top', {
241
- 'navbar--dark': style === 'dark',
242
- 'navbar--primary': style === 'primary',
243
- 'navbar-sidebar--show': mobileSidebar.shown,
244
- [styles.navbarHideable]: hideOnScroll,
245
- [styles.navbarHidden]: hideOnScroll && !isNavbarVisible,
246
- })}>
247
- <div className="navbar__inner">
248
- <div className="navbar__items">
249
- {(items?.length > 0 || activeDocPlugin) && (
250
- <button
251
- aria-label="Navigation bar toggle"
252
- className="navbar__toggle clean-btn"
253
- type="button"
254
- tabIndex={0}
255
- onClick={mobileSidebar.toggle}
256
- onKeyDown={mobileSidebar.toggle}>
257
- <IconMenu />
258
- </button>
259
- )}
260
- <Logo
261
- className="navbar__brand"
262
- imageClassName="navbar__logo"
263
- titleClassName="navbar__title"
264
- />
265
- {leftItems.map((item, i) => (
266
- <NavbarItem {...item} key={i} />
267
- ))}
268
- </div>
269
- <div className="navbar__items navbar__items--right">
270
- {rightItems.map((item, i) => (
271
- <NavbarItem {...item} key={i} />
272
- ))}
273
- {!colorModeToggle.disabled && (
274
- <ColorModeToggle
275
- className={styles.toggle}
276
- checked={colorModeToggle.isDarkTheme}
277
- onChange={colorModeToggle.toggle}
278
- />
279
- )}
280
- {!hasSearchNavbarItem && <SearchBar />}
281
- </div>
282
- </div>
283
-
284
- <div
285
- role="presentation"
286
- className="navbar-sidebar__backdrop"
287
- onClick={mobileSidebar.toggle}
288
- />
289
-
290
- {mobileSidebar.shouldRender && (
291
- <NavbarMobileSidebar
292
- sidebarShown={mobileSidebar.shown}
293
- toggleSidebar={mobileSidebar.toggle}
294
- />
295
- )}
296
- </nav>
14
+ <NavbarLayout>
15
+ <NavbarContent />
16
+ </NavbarLayout>
297
17
  );
298
18
  }
@@ -41,7 +41,7 @@ function DefaultNavbarItemDesktop({
41
41
 
42
42
  function DefaultNavbarItemMobile({
43
43
  className,
44
- isDropdownItem: _isDropdownItem,
44
+ isDropdownItem,
45
45
  ...props
46
46
  }: DesktopOrMobileNavBarItemProps) {
47
47
  return (
@@ -53,7 +53,7 @@ function DefaultNavbarItemMobile({
53
53
 
54
54
  export default function DefaultNavbarItem({
55
55
  mobile = false,
56
- position: _position, // Need to destructure position from props so that it doesn't get passed on.
56
+ position, // Need to destructure position from props so that it doesn't get passed on.
57
57
  ...props
58
58
  }: Props): JSX.Element {
59
59
  const Comp = mobile ? DefaultNavbarItemMobile : DefaultNavbarItemDesktop;
@@ -85,6 +85,9 @@ function DropdownNavbarItemDesktop({
85
85
  'dropdown--show': showDropdown,
86
86
  })}>
87
87
  <NavbarNavLink
88
+ aria-haspopup="true"
89
+ aria-expanded={showDropdown}
90
+ role="button"
88
91
  href={props.to ? undefined : '#'}
89
92
  className={clsx('navbar__link', className)}
90
93
  {...props}
@@ -107,7 +110,13 @@ function DropdownNavbarItemDesktop({
107
110
  setShowDropdown(false);
108
111
  const nextNavbarItem = dropdownRef.current!.nextElementSibling;
109
112
  if (nextNavbarItem) {
110
- (nextNavbarItem as HTMLElement).focus();
113
+ const targetItem =
114
+ nextNavbarItem instanceof HTMLAnchorElement
115
+ ? nextNavbarItem
116
+ : // Next item is another dropdown; focus on the inner
117
+ // anchor element instead so there's outline
118
+ nextNavbarItem.querySelector('a');
119
+ (targetItem as HTMLElement).focus();
111
120
  }
112
121
  }
113
122
  }}
@@ -124,7 +133,7 @@ function DropdownNavbarItemDesktop({
124
133
  function DropdownNavbarItemMobile({
125
134
  items,
126
135
  className,
127
- position: _position, // Need to destructure position from props so that it doesn't get passed on.
136
+ position, // Need to destructure position from props so that it doesn't get passed on.
128
137
  ...props
129
138
  }: DesktopOrMobileNavBarItemProps) {
130
139
  const localPathname = useLocalPathname();
@@ -28,7 +28,7 @@ export default function LocaleDropdownNavbarItem({
28
28
  const alternatePageUtils = useAlternatePageUtils();
29
29
 
30
30
  function getLocaleLabel(locale: string) {
31
- return localeConfigs[locale].label;
31
+ return localeConfigs[locale]!.label;
32
32
  }
33
33
 
34
34
  const localeItems = locales.map((locale): LinkLikeNavbarItemProps => {
@@ -55,13 +55,9 @@ export default function NavbarNavLink({
55
55
  : null),
56
56
  })}
57
57
  {...props}>
58
- {isExternalLink ? (
59
- <span>
60
- {label}
61
- <IconExternalLink {...(isDropdownLink && {width: 12, height: 12})} />
62
- </span>
63
- ) : (
64
- label
58
+ {label}
59
+ {isExternalLink && (
60
+ <IconExternalLink {...(isDropdownLink && {width: 12, height: 12})} />
65
61
  )}
66
62
  </Link>
67
63
  );
@@ -14,12 +14,11 @@ import LocaleDropdownNavbarItem from '@theme/NavbarItem/LocaleDropdownNavbarItem
14
14
  import SearchNavbarItem from '@theme/NavbarItem/SearchNavbarItem';
15
15
  import type {Types, Props} from '@theme/NavbarItem';
16
16
 
17
- const NavbarItemComponents: Record<
18
- Exclude<Types, undefined>,
17
+ const NavbarItemComponents: {
19
18
  // Not really worth typing, as we pass all props down immediately
20
19
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
- () => (props: any) => JSX.Element
22
- > = {
20
+ [type in Exclude<Types, undefined>]: () => (props: any) => JSX.Element;
21
+ } = {
23
22
  default: () => DefaultNavbarItem,
24
23
  localeDropdown: () => LocaleDropdownNavbarItem,
25
24
  search: () => SearchNavbarItem,
@@ -8,42 +8,47 @@
8
8
  import React from 'react';
9
9
  import Layout from '@theme/Layout';
10
10
  import Translate, {translate} from '@docusaurus/Translate';
11
+ import {PageMetadata} from '@docusaurus/theme-common';
11
12
 
12
13
  export default function NotFound(): JSX.Element {
13
14
  return (
14
- <Layout
15
- title={translate({
16
- id: 'theme.NotFound.title',
17
- message: 'Page Not Found',
18
- })}>
19
- <main className="container margin-vert--xl">
20
- <div className="row">
21
- <div className="col col--6 col--offset-3">
22
- <h1 className="hero__title">
23
- <Translate
24
- id="theme.NotFound.title"
25
- description="The title of the 404 page">
26
- Page Not Found
27
- </Translate>
28
- </h1>
29
- <p>
30
- <Translate
31
- id="theme.NotFound.p1"
32
- description="The first paragraph of the 404 page">
33
- We could not find what you were looking for.
34
- </Translate>
35
- </p>
36
- <p>
37
- <Translate
38
- id="theme.NotFound.p2"
39
- description="The 2nd paragraph of the 404 page">
40
- Please contact the owner of the site that linked you to the
41
- original URL and let them know their link is broken.
42
- </Translate>
43
- </p>
15
+ <>
16
+ <PageMetadata
17
+ title={translate({
18
+ id: 'theme.NotFound.title',
19
+ message: 'Page Not Found',
20
+ })}
21
+ />
22
+ <Layout>
23
+ <main className="container margin-vert--xl">
24
+ <div className="row">
25
+ <div className="col col--6 col--offset-3">
26
+ <h1 className="hero__title">
27
+ <Translate
28
+ id="theme.NotFound.title"
29
+ description="The title of the 404 page">
30
+ Page Not Found
31
+ </Translate>
32
+ </h1>
33
+ <p>
34
+ <Translate
35
+ id="theme.NotFound.p1"
36
+ description="The first paragraph of the 404 page">
37
+ We could not find what you were looking for.
38
+ </Translate>
39
+ </p>
40
+ <p>
41
+ <Translate
42
+ id="theme.NotFound.p2"
43
+ description="The 2nd paragraph of the 404 page">
44
+ Please contact the owner of the site that linked you to the
45
+ original URL and let them know their link is broken.
46
+ </Translate>
47
+ </p>
48
+ </div>
44
49
  </div>
45
- </div>
46
- </main>
47
- </Layout>
50
+ </main>
51
+ </Layout>
52
+ </>
48
53
  );
49
54
  }
@@ -9,19 +9,18 @@ import React from 'react';
9
9
  import Head from '@docusaurus/Head';
10
10
  import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
11
11
  import useBaseUrl from '@docusaurus/useBaseUrl';
12
- import type {Props} from '@theme/Layout';
13
12
  import SearchMetadata from '@theme/SearchMetadata';
14
- import Seo from '@theme/Seo';
15
13
  import {
14
+ PageMetadata,
16
15
  DEFAULT_SEARCH_TAG,
17
- useTitleFormatter,
18
16
  useAlternatePageUtils,
19
17
  useThemeConfig,
20
18
  keyboardFocusedClassName,
21
19
  } from '@docusaurus/theme-common';
22
20
  import {useLocation} from '@docusaurus/router';
23
21
 
24
- // Useful for SEO
22
+ // TODO move to SiteMetadataDefaults or theme-common ?
23
+ // Useful for i18n/SEO
25
24
  // See https://developers.google.com/search/docs/advanced/crawling/localized-versions
26
25
  // See https://github.com/facebook/docusaurus/issues/3317
27
26
  function AlternateLangHeaders(): JSX.Element {
@@ -66,6 +65,7 @@ function useDefaultCanonicalUrl() {
66
65
  return siteUrl + useBaseUrl(pathname);
67
66
  }
68
67
 
68
+ // TODO move to SiteMetadataDefaults or theme-common ?
69
69
  function CanonicalUrlHeaders({permalink}: {permalink?: string}) {
70
70
  const {
71
71
  siteConfig: {url: siteUrl},
@@ -83,45 +83,31 @@ function CanonicalUrlHeaders({permalink}: {permalink?: string}) {
83
83
  );
84
84
  }
85
85
 
86
- export default function LayoutHead(props: Props): JSX.Element {
86
+ export default function SiteMetadata(): JSX.Element {
87
87
  const {
88
- siteConfig: {favicon},
89
- i18n: {currentLocale, localeConfigs},
88
+ i18n: {currentLocale},
90
89
  } = useDocusaurusContext();
90
+
91
+ // TODO maybe move these 2 themeConfig to siteConfig?
92
+ // These seems useful for other themes as well
91
93
  const {metadata, image: defaultImage} = useThemeConfig();
92
- const {title, description, image, keywords, searchMetadata} = props;
93
- const faviconUrl = useBaseUrl(favicon);
94
- const pageTitle = useTitleFormatter(title);
95
- const {htmlLang, direction: htmlDir} = localeConfigs[currentLocale];
96
94
 
97
95
  return (
98
96
  <>
99
97
  <Head>
100
- <html lang={htmlLang} dir={htmlDir} />
101
- {favicon && <link rel="icon" href={faviconUrl} />}
102
- <title>{pageTitle}</title>
103
- <meta property="og:title" content={pageTitle} />
104
98
  <meta name="twitter:card" content="summary_large_image" />
105
99
  {/* The keyboard focus class name need to be applied when SSR so links
106
100
  are outlined when JS is disabled */}
107
101
  <body className={keyboardFocusedClassName} />
108
102
  </Head>
109
103
 
110
- {/* image can override the default image */}
111
- {defaultImage && <Seo image={defaultImage} />}
112
- {image && <Seo image={image} />}
113
-
114
- <Seo description={description} keywords={keywords} />
104
+ {defaultImage && <PageMetadata image={defaultImage} />}
115
105
 
116
106
  <CanonicalUrlHeaders />
117
107
 
118
108
  <AlternateLangHeaders />
119
109
 
120
- <SearchMetadata
121
- tag={DEFAULT_SEARCH_TAG}
122
- locale={currentLocale}
123
- {...searchMetadata}
124
- />
110
+ <SearchMetadata tag={DEFAULT_SEARCH_TAG} locale={currentLocale} />
125
111
 
126
112
  <Head
127
113
  // it's important to have an additional <Head> element here,
@@ -27,9 +27,7 @@ export default function TOCCollapsible({
27
27
  <div
28
28
  className={clsx(
29
29
  styles.tocCollapsible,
30
- {
31
- [styles.tocCollapsibleExpanded]: !collapsed,
32
- },
30
+ !collapsed && styles.tocCollapsibleExpanded,
33
31
  className,
34
32
  )}>
35
33
  <button
@@ -8,7 +8,6 @@
8
8
  import React, {
9
9
  useState,
10
10
  cloneElement,
11
- Children,
12
11
  isValidElement,
13
12
  type ReactElement,
14
13
  } from 'react';
@@ -40,7 +39,7 @@ function TabsComponent(props: Props): JSX.Element {
40
39
  groupId,
41
40
  className,
42
41
  } = props;
43
- const children = Children.map(props.children, (child) => {
42
+ const children = React.Children.map(props.children, (child) => {
44
43
  if (isValidElement(child) && isTabItem(child)) {
45
44
  return child;
46
45
  }
@@ -108,7 +107,7 @@ function TabsComponent(props: Props): JSX.Element {
108
107
  ) => {
109
108
  const newTab = event.currentTarget;
110
109
  const newTabIndex = tabRefs.indexOf(newTab);
111
- const newTabValue = values[newTabIndex].value;
110
+ const newTabValue = values[newTabIndex]!.value;
112
111
 
113
112
  if (newTabValue !== selectedValue) {
114
113
  blockElementScrollPositionUntilNextRender(newTab);
@@ -126,12 +125,12 @@ function TabsComponent(props: Props): JSX.Element {
126
125
  switch (event.key) {
127
126
  case 'ArrowRight': {
128
127
  const nextTab = tabRefs.indexOf(event.currentTarget) + 1;
129
- focusElement = tabRefs[nextTab] || tabRefs[0];
128
+ focusElement = tabRefs[nextTab] || tabRefs[0]!;
130
129
  break;
131
130
  }
132
131
  case 'ArrowLeft': {
133
132
  const prevTab = tabRefs.indexOf(event.currentTarget) - 1;
134
- focusElement = tabRefs[prevTab] || tabRefs[tabRefs.length - 1];
133
+ focusElement = tabRefs[prevTab] || tabRefs[tabRefs.length - 1]!;
135
134
  break;
136
135
  }
137
136
  default:
@@ -181,7 +180,7 @@ function TabsComponent(props: Props): JSX.Element {
181
180
  cloneElement(
182
181
  children.filter(
183
182
  (tabItem) => tabItem.props.value === selectedValue,
184
- )[0],
183
+ )[0]!,
185
184
  {className: 'margin-vert--md'},
186
185
  )
187
186
  ) : (
@@ -18,10 +18,10 @@ export default function Tag(props: Props): JSX.Element {
18
18
  return (
19
19
  <Link
20
20
  href={permalink}
21
- className={clsx(styles.tag, {
22
- [styles.tagRegular]: !count,
23
- [styles.tagWithCount]: count,
24
- })}>
21
+ className={clsx(
22
+ styles.tag,
23
+ count ? styles.tagWithCount : styles.tagRegular,
24
+ )}>
25
25
  {name}
26
26
  {count && <span>{count}</span>}
27
27
  </Link>
@@ -16,12 +16,13 @@ import styles from './styles.module.css';
16
16
 
17
17
  export default function ThemedImage(props: Props): JSX.Element {
18
18
  const isBrowser = useIsBrowser();
19
- const {isDarkTheme} = useColorMode();
20
- const {sources, className, alt = '', ...propsRest} = props;
19
+ const {colorMode} = useColorMode();
20
+ const {sources, className, alt, ...propsRest} = props;
21
21
 
22
22
  type SourceName = keyof Props['sources'];
23
23
 
24
- const clientThemes: SourceName[] = isDarkTheme ? ['dark'] : ['light'];
24
+ const clientThemes: SourceName[] =
25
+ colorMode === 'dark' ? ['dark'] : ['light'];
25
26
 
26
27
  const renderedSourceNames: SourceName[] = isBrowser
27
28
  ? clientThemes