@docusaurus/theme-common 2.1.0 → 2.3.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 (54) hide show
  1. package/lib/hooks/useHideableNavbar.d.ts.map +1 -1
  2. package/lib/hooks/useHideableNavbar.js +6 -1
  3. package/lib/hooks/useHideableNavbar.js.map +1 -1
  4. package/lib/hooks/useSearchPage.d.ts.map +1 -1
  5. package/lib/hooks/useSearchPage.js +4 -2
  6. package/lib/hooks/useSearchPage.js.map +1 -1
  7. package/lib/index.d.ts +3 -1
  8. package/lib/index.d.ts.map +1 -1
  9. package/lib/index.js +3 -1
  10. package/lib/index.js.map +1 -1
  11. package/lib/internal.d.ts +3 -3
  12. package/lib/internal.d.ts.map +1 -1
  13. package/lib/internal.js +2 -3
  14. package/lib/internal.js.map +1 -1
  15. package/lib/utils/admonitionUtils.d.ts +12 -0
  16. package/lib/utils/admonitionUtils.d.ts.map +1 -0
  17. package/lib/utils/admonitionUtils.js +33 -0
  18. package/lib/utils/admonitionUtils.js.map +1 -0
  19. package/lib/utils/historyUtils.d.ts +12 -1
  20. package/lib/utils/historyUtils.d.ts.map +1 -1
  21. package/lib/utils/historyUtils.js +23 -0
  22. package/lib/utils/historyUtils.js.map +1 -1
  23. package/lib/utils/skipToContentUtils.d.ts +17 -0
  24. package/lib/utils/skipToContentUtils.d.ts.map +1 -0
  25. package/lib/utils/skipToContentUtils.js +71 -0
  26. package/lib/utils/skipToContentUtils.js.map +1 -0
  27. package/lib/utils/storageUtils.d.ts +4 -0
  28. package/lib/utils/storageUtils.d.ts.map +1 -1
  29. package/lib/utils/storageUtils.js +70 -7
  30. package/lib/utils/storageUtils.js.map +1 -1
  31. package/lib/utils/tabsUtils.d.ts +46 -0
  32. package/lib/utils/tabsUtils.d.ts.map +1 -0
  33. package/lib/utils/tabsUtils.js +151 -0
  34. package/lib/utils/tabsUtils.js.map +1 -0
  35. package/package.json +11 -10
  36. package/src/hooks/useHideableNavbar.ts +7 -1
  37. package/src/hooks/useSearchPage.ts +10 -5
  38. package/src/index.ts +12 -1
  39. package/src/internal.ts +7 -6
  40. package/src/utils/admonitionUtils.tsx +43 -0
  41. package/src/utils/historyUtils.ts +29 -1
  42. package/src/utils/skipToContentUtils.tsx +103 -0
  43. package/src/utils/storageUtils.ts +108 -7
  44. package/src/utils/tabsUtils.tsx +266 -0
  45. package/lib/contexts/tabGroupChoice.d.ts +0 -21
  46. package/lib/contexts/tabGroupChoice.d.ts.map +0 -1
  47. package/lib/contexts/tabGroupChoice.js +0 -49
  48. package/lib/contexts/tabGroupChoice.js.map +0 -1
  49. package/lib/hooks/useSkipToContent.d.ts +0 -25
  50. package/lib/hooks/useSkipToContent.d.ts.map +0 -1
  51. package/lib/hooks/useSkipToContent.js +0 -35
  52. package/lib/hooks/useSkipToContent.js.map +0 -1
  53. package/src/contexts/tabGroupChoice.tsx +0 -85
  54. package/src/hooks/useSkipToContent.ts +0 -58
@@ -0,0 +1,46 @@
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 ReactNode, type ReactElement } from 'react';
8
+ /**
9
+ * TabValue is the "config" of a given Tab
10
+ * Provided through <Tabs> "values" prop or through the children <TabItem> props
11
+ */
12
+ export interface TabValue {
13
+ readonly value: string;
14
+ readonly label?: string;
15
+ readonly attributes?: {
16
+ [key: string]: unknown;
17
+ };
18
+ readonly default?: boolean;
19
+ }
20
+ export interface TabsProps {
21
+ readonly lazy?: boolean;
22
+ readonly block?: boolean;
23
+ readonly children: readonly ReactElement<TabItemProps>[];
24
+ readonly defaultValue?: string | null;
25
+ readonly values?: readonly TabValue[];
26
+ readonly groupId?: string;
27
+ readonly className?: string;
28
+ readonly queryString?: string | boolean;
29
+ }
30
+ export interface TabItemProps {
31
+ readonly children: ReactNode;
32
+ readonly value: string;
33
+ readonly default?: boolean;
34
+ readonly label?: string;
35
+ readonly hidden?: boolean;
36
+ readonly className?: string;
37
+ readonly attributes?: {
38
+ [key: string]: unknown;
39
+ };
40
+ }
41
+ export declare function useTabs(props: TabsProps): {
42
+ selectedValue: string;
43
+ selectValue: (value: string) => void;
44
+ tabValues: readonly TabValue[];
45
+ };
46
+ //# sourceMappingURL=tabsUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabsUtils.d.ts","sourceRoot":"","sources":["../../src/utils/tabsUtils.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAc,EAMZ,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,OAAO,CAAC;AAKf;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAC,CAAC;IAC/C,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,CAAC,YAAY,CAAC,EAAE,CAAC;IACzD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACzC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAC,CAAC;CAChD;AAuKD,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;CAChC,CA4CA"}
@@ -0,0 +1,151 @@
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 React, { isValidElement, useCallback, useEffect, useState, useMemo, } from 'react';
8
+ import { useHistory } from '@docusaurus/router';
9
+ import { useQueryStringValue } from '@docusaurus/theme-common/internal';
10
+ import { duplicates, useStorageSlot } from '../index';
11
+ // A very rough duck type, but good enough to guard against mistakes while
12
+ // allowing customization
13
+ function isTabItem(comp) {
14
+ return 'value' in comp.props;
15
+ }
16
+ function ensureValidChildren(children) {
17
+ return React.Children.map(children, (child) => {
18
+ if (isValidElement(child) && isTabItem(child)) {
19
+ return child;
20
+ }
21
+ // child.type.name will give non-sensical values in prod because of
22
+ // minification, but we assume it won't throw in prod.
23
+ throw new Error(`Docusaurus error: Bad <Tabs> child <${
24
+ // @ts-expect-error: guarding against unexpected cases
25
+ typeof child.type === 'string' ? child.type : child.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`);
26
+ });
27
+ }
28
+ function extractChildrenTabValues(children) {
29
+ return ensureValidChildren(children).map(({ props: { value, label, attributes, default: isDefault } }) => ({
30
+ value,
31
+ label,
32
+ attributes,
33
+ default: isDefault,
34
+ }));
35
+ }
36
+ function ensureNoDuplicateValue(values) {
37
+ const dup = duplicates(values, (a, b) => a.value === b.value);
38
+ if (dup.length > 0) {
39
+ throw new Error(`Docusaurus error: Duplicate values "${dup
40
+ .map((a) => a.value)
41
+ .join(', ')}" found in <Tabs>. Every value needs to be unique.`);
42
+ }
43
+ }
44
+ function useTabValues(props) {
45
+ const { values: valuesProp, children } = props;
46
+ return useMemo(() => {
47
+ const values = valuesProp ?? extractChildrenTabValues(children);
48
+ ensureNoDuplicateValue(values);
49
+ return values;
50
+ }, [valuesProp, children]);
51
+ }
52
+ function isValidValue({ value, tabValues, }) {
53
+ return tabValues.some((a) => a.value === value);
54
+ }
55
+ function getInitialStateValue({ defaultValue, tabValues, }) {
56
+ if (tabValues.length === 0) {
57
+ throw new Error('Docusaurus error: the <Tabs> component requires at least one <TabItem> children component');
58
+ }
59
+ if (defaultValue) {
60
+ // Warn user about passing incorrect defaultValue as prop.
61
+ if (!isValidValue({ value: defaultValue, tabValues })) {
62
+ throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${defaultValue}" but none of its children has the corresponding value. Available values are: ${tabValues
63
+ .map((a) => a.value)
64
+ .join(', ')}. If you intend to show no default tab, use defaultValue={null} instead.`);
65
+ }
66
+ return defaultValue;
67
+ }
68
+ const defaultTabValue = tabValues.find((tabValue) => tabValue.default) ?? tabValues[0];
69
+ if (!defaultTabValue) {
70
+ throw new Error('Unexpected error: 0 tabValues');
71
+ }
72
+ return defaultTabValue.value;
73
+ }
74
+ function getStorageKey(groupId) {
75
+ if (!groupId) {
76
+ return null;
77
+ }
78
+ return `docusaurus.tab.${groupId}`;
79
+ }
80
+ function getQueryStringKey({ queryString = false, groupId, }) {
81
+ if (typeof queryString === 'string') {
82
+ return queryString;
83
+ }
84
+ if (queryString === false) {
85
+ return null;
86
+ }
87
+ if (queryString === true && !groupId) {
88
+ throw new Error(`Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".`);
89
+ }
90
+ return groupId ?? null;
91
+ }
92
+ function useTabQueryString({ queryString = false, groupId, }) {
93
+ const history = useHistory();
94
+ const key = getQueryStringKey({ queryString, groupId });
95
+ const value = useQueryStringValue(key);
96
+ const setValue = useCallback((newValue) => {
97
+ if (!key) {
98
+ return; // no-op
99
+ }
100
+ const searchParams = new URLSearchParams(history.location.search);
101
+ searchParams.set(key, newValue);
102
+ history.replace({ ...history.location, search: searchParams.toString() });
103
+ }, [key, history]);
104
+ return [value, setValue];
105
+ }
106
+ function useTabStorage({ groupId }) {
107
+ const key = getStorageKey(groupId);
108
+ const [value, storageSlot] = useStorageSlot(key);
109
+ const setValue = useCallback((newValue) => {
110
+ if (!key) {
111
+ return; // no-op
112
+ }
113
+ storageSlot.set(newValue);
114
+ }, [key, storageSlot]);
115
+ return [value, setValue];
116
+ }
117
+ export function useTabs(props) {
118
+ const { defaultValue, queryString = false, groupId } = props;
119
+ const tabValues = useTabValues(props);
120
+ const [selectedValue, setSelectedValue] = useState(() => getInitialStateValue({ defaultValue, tabValues }));
121
+ const [queryStringValue, setQueryString] = useTabQueryString({
122
+ queryString,
123
+ groupId,
124
+ });
125
+ const [storageValue, setStorageValue] = useTabStorage({
126
+ groupId,
127
+ });
128
+ // We sync valid querystring/storage value to state on change + hydration
129
+ const valueToSync = (() => {
130
+ const value = queryStringValue ?? storageValue;
131
+ if (!isValidValue({ value, tabValues })) {
132
+ return null;
133
+ }
134
+ return value;
135
+ })();
136
+ useEffect(() => {
137
+ if (valueToSync) {
138
+ setSelectedValue(valueToSync);
139
+ }
140
+ }, [valueToSync]);
141
+ const selectValue = useCallback((newValue) => {
142
+ if (!isValidValue({ value: newValue, tabValues })) {
143
+ throw new Error(`Can't select invalid tab value=${newValue}`);
144
+ }
145
+ setSelectedValue(newValue);
146
+ setQueryString(newValue);
147
+ setStorageValue(newValue);
148
+ }, [setQueryString, setStorageValue, tabValues]);
149
+ return { selectedValue, selectValue, tabValues };
150
+ }
151
+ //# sourceMappingURL=tabsUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabsUtils.js","sourceRoot":"","sources":["../../src/utils/tabsUtils.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/theme-common",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "Common code for Docusaurus themes.",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -30,12 +30,12 @@
30
30
  },
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
- "@docusaurus/mdx-loader": "2.1.0",
34
- "@docusaurus/module-type-aliases": "2.1.0",
35
- "@docusaurus/plugin-content-blog": "2.1.0",
36
- "@docusaurus/plugin-content-docs": "2.1.0",
37
- "@docusaurus/plugin-content-pages": "2.1.0",
38
- "@docusaurus/utils": "2.1.0",
33
+ "@docusaurus/mdx-loader": "2.3.0",
34
+ "@docusaurus/module-type-aliases": "2.3.0",
35
+ "@docusaurus/plugin-content-blog": "2.3.0",
36
+ "@docusaurus/plugin-content-docs": "2.3.0",
37
+ "@docusaurus/plugin-content-pages": "2.3.0",
38
+ "@docusaurus/utils": "2.3.0",
39
39
  "@types/history": "^4.7.11",
40
40
  "@types/react": "*",
41
41
  "@types/react-router-config": "*",
@@ -43,11 +43,12 @@
43
43
  "parse-numeric-range": "^1.3.0",
44
44
  "prism-react-renderer": "^1.3.5",
45
45
  "tslib": "^2.4.0",
46
+ "use-sync-external-store": "^1.2.0",
46
47
  "utility-types": "^3.10.0"
47
48
  },
48
49
  "devDependencies": {
49
- "@docusaurus/core": "2.1.0",
50
- "@docusaurus/types": "2.1.0",
50
+ "@docusaurus/core": "2.3.0",
51
+ "@docusaurus/types": "2.3.0",
51
52
  "fs-extra": "^10.1.0",
52
53
  "lodash": "^4.17.21"
53
54
  },
@@ -58,5 +59,5 @@
58
59
  "engines": {
59
60
  "node": ">=16.14"
60
61
  },
61
- "gitHead": "be9b0942641184213485eba7fd75ceb0b328d3f4"
62
+ "gitHead": "ad477781bdca6a11fa9c6daef5048bdcec0ee37e"
62
63
  }
@@ -62,7 +62,13 @@ export function useHideableNavbar(hideOnScroll: boolean): {
62
62
  return;
63
63
  }
64
64
 
65
- if (locationChangeEvent.location.hash) {
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) {
66
72
  isFocusedAnchor.current = true;
67
73
  setIsNavbarVisible(false);
68
74
  return;
@@ -8,6 +8,7 @@
8
8
  import {useCallback, useEffect, useState} from 'react';
9
9
  import {useHistory} from '@docusaurus/router';
10
10
  import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
11
+ import type {ThemeConfig as AlgoliaThemeConfig} from '@docusaurus/theme-search-algolia';
11
12
 
12
13
  const SEARCH_PARAM_QUERY = 'q';
13
14
 
@@ -31,8 +32,11 @@ export function useSearchPage(): {
31
32
  } {
32
33
  const history = useHistory();
33
34
  const {
34
- siteConfig: {baseUrl},
35
+ siteConfig: {baseUrl, themeConfig},
35
36
  } = useDocusaurusContext();
37
+ const {
38
+ algolia: {searchPagePath},
39
+ } = themeConfig as AlgoliaThemeConfig;
36
40
 
37
41
  const [searchQuery, setSearchQueryState] = useState('');
38
42
 
@@ -65,10 +69,11 @@ export function useSearchPage(): {
65
69
  const generateSearchPageLink = useCallback(
66
70
  (targetSearchQuery: string) =>
67
71
  // Refer to https://github.com/facebook/docusaurus/pull/2838
68
- `${baseUrl}search?${SEARCH_PARAM_QUERY}=${encodeURIComponent(
69
- targetSearchQuery,
70
- )}`,
71
- [baseUrl],
72
+ // Note: if searchPagePath is falsy, useSearchPage() will not be called
73
+ `${baseUrl}${
74
+ searchPagePath as string
75
+ }?${SEARCH_PARAM_QUERY}=${encodeURIComponent(targetSearchQuery)}`,
76
+ [baseUrl, searchPagePath],
72
77
  );
73
78
 
74
79
  return {
package/src/index.ts CHANGED
@@ -24,7 +24,11 @@ export {
24
24
  type ColorModeConfig,
25
25
  } from './utils/useThemeConfig';
26
26
 
27
- export {createStorageSlot, listStorageKeys} from './utils/storageUtils';
27
+ export {
28
+ createStorageSlot,
29
+ useStorageSlot,
30
+ listStorageKeys,
31
+ } from './utils/storageUtils';
28
32
 
29
33
  export {useContextualSearchFilters} from './utils/searchUtils';
30
34
 
@@ -78,3 +82,10 @@ export {duplicates, uniq} from './utils/jsUtils';
78
82
  export {usePrismTheme} from './hooks/usePrismTheme';
79
83
 
80
84
  export {useDocsPreferredVersion} from './contexts/docsPreferredVersion';
85
+
86
+ export {processAdmonitionProps} from './utils/admonitionUtils';
87
+
88
+ export {
89
+ SkipToContentFallbackId,
90
+ SkipToContentLink,
91
+ } from './utils/skipToContentUtils';
package/src/internal.ts CHANGED
@@ -42,10 +42,8 @@ export {
42
42
  useAnnouncementBar,
43
43
  } from './contexts/announcementBar';
44
44
 
45
- export {
46
- useTabGroupChoice,
47
- TabGroupChoiceProvider,
48
- } from './contexts/tabGroupChoice';
45
+ export {useTabs} from './utils/tabsUtils';
46
+ export type {TabValue, TabsProps, TabItemProps} from './utils/tabsUtils';
49
47
 
50
48
  export {useNavbarMobileSidebar} from './contexts/navbarMobileSidebar';
51
49
  export {useNavbarSecondaryMenu} from './contexts/navbarSecondaryMenu/display';
@@ -82,7 +80,11 @@ export {useLocationChange} from './utils/useLocationChange';
82
80
 
83
81
  export {useLocalPathname} from './utils/useLocalPathname';
84
82
 
85
- export {useHistoryPopHandler} from './utils/historyUtils';
83
+ export {
84
+ useHistoryPopHandler,
85
+ useHistorySelector,
86
+ useQueryStringValue,
87
+ } from './utils/historyUtils';
86
88
 
87
89
  export {
88
90
  useFilteredAndTreeifiedTOC,
@@ -117,6 +119,5 @@ export {
117
119
  export {useLockBodyScroll} from './hooks/useLockBodyScroll';
118
120
  export {useSearchPage} from './hooks/useSearchPage';
119
121
  export {useCodeWordWrap} from './hooks/useCodeWordWrap';
120
- export {useSkipToContent} from './hooks/useSkipToContent';
121
122
  export {getPrismCssVariables} from './utils/codeBlockUtils';
122
123
  export {useBackToTopButton} from './hooks/useBackToTopButton';
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import React, {type ReactNode} from 'react';
9
+
10
+ // Workaround because it's difficult in MDX v1 to provide a MDX title as props
11
+ // See https://github.com/facebook/docusaurus/pull/7152#issuecomment-1145779682
12
+ function extractMDXAdmonitionTitle(children: ReactNode): {
13
+ mdxAdmonitionTitle: ReactNode | undefined;
14
+ rest: ReactNode;
15
+ } {
16
+ const items = React.Children.toArray(children);
17
+ const mdxAdmonitionTitle = items.find(
18
+ (item) =>
19
+ React.isValidElement(item) &&
20
+ (item.props as {mdxType: string} | null)?.mdxType ===
21
+ 'mdxAdmonitionTitle',
22
+ ) as JSX.Element | undefined;
23
+ const rest = <>{items.filter((item) => item !== mdxAdmonitionTitle)}</>;
24
+ return {
25
+ mdxAdmonitionTitle: mdxAdmonitionTitle?.props.children,
26
+ rest,
27
+ };
28
+ }
29
+
30
+ export function processAdmonitionProps<
31
+ Props extends {readonly children: ReactNode; readonly title?: ReactNode},
32
+ >(props: Props): Props {
33
+ const {mdxAdmonitionTitle, rest} = extractMDXAdmonitionTitle(props.children);
34
+ const title = props.title ?? mdxAdmonitionTitle;
35
+ return {
36
+ ...props,
37
+ // Do not return "title: undefined" prop
38
+ // this might create unwanted props overrides when merging props
39
+ // For example: {...default,...props}
40
+ ...(title && {title}),
41
+ children: rest,
42
+ };
43
+ }
@@ -7,8 +7,11 @@
7
7
 
8
8
  import {useEffect} from 'react';
9
9
  import {useHistory} from '@docusaurus/router';
10
+ // @ts-expect-error: TODO temporary until React 18 upgrade
11
+ import {useSyncExternalStore} from 'use-sync-external-store/shim';
10
12
  import {useEvent} from './reactUtils';
11
- import type {Location, Action} from 'history';
13
+
14
+ import type {History, Location, Action} from 'history';
12
15
 
13
16
  type HistoryBlockHandler = (location: Location, action: Action) => void | false;
14
17
 
@@ -43,3 +46,28 @@ export function useHistoryPopHandler(handler: HistoryBlockHandler): void {
43
46
  return undefined;
44
47
  });
45
48
  }
49
+
50
+ /**
51
+ * Permits to efficiently subscribe to a slice of the history
52
+ * See https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api
53
+ * @param selector
54
+ */
55
+ export function useHistorySelector<Value>(
56
+ selector: (history: History<unknown>) => Value,
57
+ ): Value {
58
+ const history = useHistory();
59
+ return useSyncExternalStore(history.listen, () => selector(history));
60
+ }
61
+
62
+ /**
63
+ * Permits to efficiently subscribe to a specific querystring value
64
+ * @param key
65
+ */
66
+ export function useQueryStringValue(key: string | null): string | null {
67
+ return useHistorySelector((history) => {
68
+ if (key === null) {
69
+ return null;
70
+ }
71
+ return new URLSearchParams(history.location.search).get(key);
72
+ });
73
+ }
@@ -0,0 +1,103 @@
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, {useCallback, useRef, type ComponentProps} from 'react';
9
+ import {useHistory} from '@docusaurus/router';
10
+ import {translate} from '@docusaurus/Translate';
11
+ import {useLocationChange} from './useLocationChange';
12
+
13
+ /**
14
+ * The id of the element that should become focused on a page
15
+ * that does not have a <main> html tag.
16
+ * Focusing the Docusaurus Layout children is a reasonable fallback.
17
+ */
18
+ export const SkipToContentFallbackId = 'docusaurus_skipToContent_fallback';
19
+
20
+ /**
21
+ * Returns the skip to content element to focus when the link is clicked.
22
+ */
23
+ function getSkipToContentTarget(): HTMLElement | null {
24
+ return (
25
+ // Try to focus the <main> in priority
26
+ // Note: this will only work if JS is enabled
27
+ // See https://github.com/facebook/docusaurus/issues/6411#issuecomment-1284136069
28
+ document.querySelector('main:first-of-type') ??
29
+ // Then try to focus the fallback element (usually the Layout children)
30
+ document.getElementById(SkipToContentFallbackId)
31
+ );
32
+ }
33
+
34
+ function programmaticFocus(el: HTMLElement) {
35
+ el.setAttribute('tabindex', '-1');
36
+ el.focus();
37
+ el.removeAttribute('tabindex');
38
+ }
39
+
40
+ /** This hook wires the logic for a skip-to-content link. */
41
+ function useSkipToContent(): {
42
+ /**
43
+ * The ref to the container. On page transition, the container will be focused
44
+ * so that keyboard navigators can instantly interact with the link and jump
45
+ * to content.
46
+ */
47
+ containerRef: React.RefObject<HTMLDivElement>;
48
+ /**
49
+ * Callback fired when the skip to content link has been clicked.
50
+ * It will programmatically focus the main content.
51
+ */
52
+ onClick: (e: React.MouseEvent<HTMLAnchorElement>) => void;
53
+ } {
54
+ const containerRef = useRef<HTMLDivElement>(null);
55
+ const {action} = useHistory();
56
+
57
+ const onClick = useCallback((e: React.MouseEvent<HTMLAnchorElement>) => {
58
+ e.preventDefault();
59
+ const targetElement = getSkipToContentTarget();
60
+ if (targetElement) {
61
+ programmaticFocus(targetElement);
62
+ }
63
+ }, []);
64
+
65
+ // "Reset" focus when navigating.
66
+ // See https://github.com/facebook/docusaurus/pull/8204#issuecomment-1276547558
67
+ useLocationChange(({location}) => {
68
+ if (containerRef.current && !location.hash && action === 'PUSH') {
69
+ programmaticFocus(containerRef.current);
70
+ }
71
+ });
72
+
73
+ return {containerRef, onClick};
74
+ }
75
+
76
+ const DefaultSkipToContentLabel = translate({
77
+ id: 'theme.common.skipToMainContent',
78
+ description:
79
+ 'The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation',
80
+ message: 'Skip to main content',
81
+ });
82
+
83
+ type SkipToContentLinkProps = Omit<ComponentProps<'a'>, 'href' | 'onClick'>;
84
+
85
+ export function SkipToContentLink(props: SkipToContentLinkProps): JSX.Element {
86
+ const linkLabel = props.children ?? DefaultSkipToContentLabel;
87
+ const {containerRef, onClick} = useSkipToContent();
88
+ return (
89
+ <div
90
+ ref={containerRef}
91
+ role="region"
92
+ aria-label={DefaultSkipToContentLabel}>
93
+ <a
94
+ {...props}
95
+ // Note this is a fallback href in case JS is disabled
96
+ // It has limitations, see https://github.com/facebook/docusaurus/issues/6411#issuecomment-1284136069
97
+ href={`#${SkipToContentFallbackId}`}
98
+ onClick={onClick}>
99
+ {linkLabel}
100
+ </a>
101
+ </div>
102
+ );
103
+ }