@docusaurus/theme-common 2.0.0-beta.8bda3b2db → 2.0.0-beta.9

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 (69) hide show
  1. package/copyUntypedFiles.js +20 -0
  2. package/lib/.tsbuildinfo +1 -1
  3. package/lib/components/Collapsible/index.d.ts +35 -0
  4. package/lib/components/Collapsible/index.js +139 -0
  5. package/lib/components/Details/index.d.ts +12 -0
  6. package/lib/components/Details/index.js +64 -0
  7. package/lib/components/Details/styles.module.css +58 -0
  8. package/lib/index.d.ts +19 -1
  9. package/lib/index.js +13 -0
  10. package/lib/utils/ThemeClassNames.d.ts +36 -12
  11. package/lib/utils/ThemeClassNames.js +36 -3
  12. package/lib/utils/announcementBarUtils.d.ts +17 -0
  13. package/lib/utils/announcementBarUtils.js +73 -0
  14. package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.js +1 -1
  15. package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.d.ts +5 -3
  16. package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.js +1 -2
  17. package/lib/utils/generalUtils.js +2 -2
  18. package/lib/utils/historyUtils.d.ts +11 -0
  19. package/lib/utils/historyUtils.js +42 -0
  20. package/lib/utils/jsUtils.d.ts +13 -0
  21. package/lib/utils/jsUtils.js +16 -0
  22. package/lib/utils/mobileSecondaryMenu.d.ts +20 -0
  23. package/lib/utils/mobileSecondaryMenu.js +51 -0
  24. package/lib/utils/reactUtils.d.ts +9 -0
  25. package/lib/utils/reactUtils.js +26 -0
  26. package/lib/utils/regexpUtils.d.ts +10 -0
  27. package/lib/utils/regexpUtils.js +16 -0
  28. package/lib/utils/scrollUtils.d.ts +52 -0
  29. package/lib/utils/scrollUtils.js +137 -0
  30. package/lib/utils/tagsUtils.d.ts +18 -0
  31. package/lib/utils/tagsUtils.js +33 -0
  32. package/lib/utils/tocUtils.d.ts +15 -0
  33. package/lib/utils/tocUtils.js +36 -0
  34. package/lib/utils/useLocalPathname.d.ts +7 -0
  35. package/lib/utils/useLocalPathname.js +16 -0
  36. package/lib/utils/useLocationChange.js +5 -9
  37. package/lib/utils/usePrevious.js +3 -2
  38. package/lib/utils/useTOCHighlight.d.ts +14 -0
  39. package/lib/utils/useTOCHighlight.js +124 -0
  40. package/lib/utils/useThemeConfig.d.ts +14 -2
  41. package/package.json +16 -12
  42. package/src/components/Collapsible/index.tsx +242 -0
  43. package/src/components/Details/index.tsx +94 -0
  44. package/src/components/Details/styles.module.css +58 -0
  45. package/src/index.ts +50 -0
  46. package/src/types.d.ts +0 -2
  47. package/src/utils/ThemeClassNames.ts +42 -4
  48. package/src/utils/__tests__/tagUtils.test.ts +66 -0
  49. package/src/utils/__tests__/tocUtils.test.ts +197 -0
  50. package/src/utils/announcementBarUtils.tsx +119 -0
  51. package/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx +4 -4
  52. package/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts +13 -14
  53. package/src/utils/generalUtils.ts +2 -2
  54. package/src/utils/historyUtils.ts +50 -0
  55. package/src/utils/jsUtils.ts +23 -0
  56. package/src/utils/mobileSecondaryMenu.tsx +116 -0
  57. package/src/utils/reactUtils.tsx +34 -0
  58. package/src/utils/regexpUtils.ts +23 -0
  59. package/src/utils/scrollUtils.tsx +238 -0
  60. package/src/utils/storageUtils.ts +1 -1
  61. package/src/utils/tagsUtils.ts +48 -0
  62. package/src/utils/tocUtils.ts +54 -0
  63. package/src/utils/useAlternatePageUtils.ts +9 -1
  64. package/src/utils/useLocalPathname.ts +20 -0
  65. package/src/utils/useLocationChange.ts +6 -10
  66. package/src/utils/usePluralForm.ts +3 -1
  67. package/src/utils/usePrevious.ts +3 -2
  68. package/src/utils/useTOCHighlight.ts +179 -0
  69. package/src/utils/useThemeConfig.ts +18 -2
@@ -0,0 +1,64 @@
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, { useRef, useState } from 'react';
8
+ import useIsBrowser from '@docusaurus/useIsBrowser';
9
+ import clsx from 'clsx';
10
+ import { useCollapsible, Collapsible } from '../Collapsible';
11
+ import styles from './styles.module.css';
12
+ function isInSummary(node) {
13
+ if (!node) {
14
+ return false;
15
+ }
16
+ return node.tagName === 'SUMMARY' || isInSummary(node.parentElement);
17
+ }
18
+ function hasParent(node, parent) {
19
+ if (!node) {
20
+ return false;
21
+ }
22
+ return node === parent || hasParent(node.parentElement, parent);
23
+ }
24
+ const Details = ({ summary, children, ...props }) => {
25
+ const isBrowser = useIsBrowser();
26
+ const detailsRef = useRef(null);
27
+ const { collapsed, setCollapsed } = useCollapsible({
28
+ initialState: !props.open,
29
+ });
30
+ // We use a separate prop because it must be set only after animation completes
31
+ // Otherwise close anim won't work
32
+ const [open, setOpen] = useState(props.open);
33
+ return (React.createElement("details", { ...props, ref: detailsRef, open: open, "data-collapsed": collapsed, className: clsx(styles.details, { [styles.isBrowser]: isBrowser }, props.className), onMouseDown: (e) => {
34
+ const target = e.target;
35
+ // Prevent a double-click to highlight summary text
36
+ if (isInSummary(target) && e.detail > 1) {
37
+ e.preventDefault();
38
+ }
39
+ }, onClick: (e) => {
40
+ e.stopPropagation(); // For isolation of multiple nested details/summary
41
+ const target = e.target;
42
+ const shouldToggle = isInSummary(target) && hasParent(target, detailsRef.current);
43
+ if (!shouldToggle) {
44
+ return;
45
+ }
46
+ e.preventDefault();
47
+ if (collapsed) {
48
+ setCollapsed(false);
49
+ setOpen(true);
50
+ }
51
+ else {
52
+ setCollapsed(true);
53
+ // setOpen(false); // Don't do this, it breaks close animation!
54
+ }
55
+ } },
56
+ summary,
57
+ React.createElement(Collapsible, { lazy: false, collapsed: collapsed, disableSSRStyle // Allows component to work fine even with JS disabled!
58
+ : true, onCollapseTransitionEnd: (newCollapsed) => {
59
+ setCollapsed(newCollapsed);
60
+ setOpen(!newCollapsed);
61
+ } },
62
+ React.createElement("div", { className: styles.collapsibleContent }, children))));
63
+ };
64
+ export default Details;
@@ -0,0 +1,58 @@
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 overriden 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
+ }
package/lib/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  export { useThemeConfig } from './utils/useThemeConfig';
8
- export type { ThemeConfig, Navbar, NavbarItem, NavbarLogo, Footer, FooterLinks, FooterLinkItem, } from './utils/useThemeConfig';
8
+ export type { ThemeConfig, UserThemeConfig, Navbar, NavbarItem, NavbarLogo, Footer, FooterLinks, FooterLinkItem, } from './utils/useThemeConfig';
9
9
  export { createStorageSlot, listStorageKeys } from './utils/storageUtils';
10
10
  export { useAlternatePageUtils } from './utils/useAlternatePageUtils';
11
11
  export { parseCodeBlockTitle } from './utils/codeBlockUtils';
@@ -16,6 +16,24 @@ export { useTitleFormatter } from './utils/generalUtils';
16
16
  export { usePluralForm } from './utils/usePluralForm';
17
17
  export { useLocationChange } from './utils/useLocationChange';
18
18
  export { usePrevious } from './utils/usePrevious';
19
+ export { useCollapsible, Collapsible } from './components/Collapsible';
20
+ export type { UseCollapsibleConfig, UseCollapsibleReturns, } from './components/Collapsible';
21
+ export { default as Details } from './components/Details';
22
+ export type { DetailsProps } from './components/Details';
23
+ export { MobileSecondaryMenuProvider, MobileSecondaryMenuFiller, useMobileSecondaryMenuRenderer, } from './utils/mobileSecondaryMenu';
24
+ export type { MobileSecondaryMenuComponent } from './utils/mobileSecondaryMenu';
19
25
  export { useDocsPreferredVersion, useDocsPreferredVersionByPluginId, } from './utils/docsPreferredVersion/useDocsPreferredVersion';
26
+ export { duplicates } from './utils/jsUtils';
20
27
  export { DocsPreferredVersionContextProvider } from './utils/docsPreferredVersion/DocsPreferredVersionProvider';
21
28
  export { ThemeClassNames } from './utils/ThemeClassNames';
29
+ export { AnnouncementBarProvider, useAnnouncementBar, } from './utils/announcementBarUtils';
30
+ export { useLocalPathname } from './utils/useLocalPathname';
31
+ export { translateTagsPageTitle, listTagsByLetters } from './utils/tagsUtils';
32
+ export type { TagLetterEntry } from './utils/tagsUtils';
33
+ export { useHistoryPopHandler } from './utils/historyUtils';
34
+ export { default as useTOCHighlight } from './utils/useTOCHighlight';
35
+ export type { TOCHighlightConfig } from './utils/useTOCHighlight';
36
+ export { useTOCFilter } from './utils/tocUtils';
37
+ export { ScrollControllerProvider, useScrollController, useScrollPosition, useScrollPositionBlocker, } from './utils/scrollUtils';
38
+ export { useIsomorphicLayoutEffect, useDynamicCallback, } from './utils/reactUtils';
39
+ export { isRegexpStringMatch } from './utils/regexpUtils';
package/lib/index.js CHANGED
@@ -15,6 +15,19 @@ export { useTitleFormatter } from './utils/generalUtils';
15
15
  export { usePluralForm } from './utils/usePluralForm';
16
16
  export { useLocationChange } from './utils/useLocationChange';
17
17
  export { usePrevious } from './utils/usePrevious';
18
+ export { useCollapsible, Collapsible } from './components/Collapsible';
19
+ export { default as Details } from './components/Details';
20
+ export { MobileSecondaryMenuProvider, MobileSecondaryMenuFiller, useMobileSecondaryMenuRenderer, } from './utils/mobileSecondaryMenu';
18
21
  export { useDocsPreferredVersion, useDocsPreferredVersionByPluginId, } from './utils/docsPreferredVersion/useDocsPreferredVersion';
22
+ export { duplicates } from './utils/jsUtils';
19
23
  export { DocsPreferredVersionContextProvider } from './utils/docsPreferredVersion/DocsPreferredVersionProvider';
20
24
  export { ThemeClassNames } from './utils/ThemeClassNames';
25
+ export { AnnouncementBarProvider, useAnnouncementBar, } from './utils/announcementBarUtils';
26
+ export { useLocalPathname } from './utils/useLocalPathname';
27
+ export { translateTagsPageTitle, listTagsByLetters } from './utils/tagsUtils';
28
+ export { useHistoryPopHandler } from './utils/historyUtils';
29
+ export { default as useTOCHighlight } from './utils/useTOCHighlight';
30
+ export { useTOCFilter } from './utils/tocUtils';
31
+ export { ScrollControllerProvider, useScrollController, useScrollPosition, useScrollPositionBlocker, } from './utils/scrollUtils';
32
+ export { useIsomorphicLayoutEffect, useDynamicCallback, } from './utils/reactUtils';
33
+ export { isRegexpStringMatch } from './utils/regexpUtils';
@@ -5,18 +5,42 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  export declare const ThemeClassNames: {
8
- page: {
9
- blogListPage: string;
10
- blogPostPage: string;
11
- blogTagsListPage: string;
12
- blogTagsPostPage: string;
13
- docPage: string;
14
- mdxPage: string;
8
+ readonly page: {
9
+ readonly blogListPage: "blog-list-page";
10
+ readonly blogPostPage: "blog-post-page";
11
+ readonly blogTagsListPage: "blog-tags-list-page";
12
+ readonly blogTagPostListPage: "blog-tags-post-list-page";
13
+ readonly docsDocPage: "docs-doc-page";
14
+ readonly docsTagsListPage: "docs-tags-list-page";
15
+ readonly docsTagDocListPage: "docs-tags-doc-list-page";
16
+ readonly mdxPage: "mdx-page";
15
17
  };
16
- wrapper: {
17
- main: string;
18
- blogPages: string;
19
- docPages: string;
20
- mdxPages: string;
18
+ readonly wrapper: {
19
+ readonly main: "main-wrapper";
20
+ readonly blogPages: "blog-wrapper";
21
+ readonly docsPages: "docs-wrapper";
22
+ readonly mdxPages: "mdx-wrapper";
21
23
  };
24
+ readonly common: {
25
+ readonly editThisPage: "theme-edit-this-page";
26
+ readonly lastUpdated: "theme-last-updated";
27
+ readonly backToTopButton: "theme-back-to-top-button";
28
+ };
29
+ readonly layout: {};
30
+ readonly docs: {
31
+ readonly docVersionBanner: "theme-doc-version-banner";
32
+ readonly docVersionBadge: "theme-doc-version-badge";
33
+ readonly docMarkdown: "theme-doc-markdown";
34
+ readonly docTocMobile: "theme-doc-toc-mobile";
35
+ readonly docTocDesktop: "theme-doc-toc-desktop";
36
+ readonly docFooter: "theme-doc-footer";
37
+ readonly docFooterTagsRow: "theme-doc-footer-tags-row";
38
+ readonly docFooterEditMetaRow: "theme-doc-footer-edit-meta-row";
39
+ readonly docSidebarMenu: "theme-doc-sidebar-menu";
40
+ readonly docSidebarItemCategory: "theme-doc-sidebar-item-category";
41
+ readonly docSidebarItemLink: "theme-doc-sidebar-item-link";
42
+ readonly docSidebarItemCategoryLevel: (level: number) => `theme-doc-sidebar-item-category-level-${number}`;
43
+ readonly docSidebarItemLinkLevel: (level: number) => `theme-doc-sidebar-item-link-level-${number}`;
44
+ };
45
+ readonly blog: {};
22
46
  };
@@ -5,19 +5,52 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  // These class names are used to style page layouts in Docusaurus
8
+ // Those are meant to be targeted by user-provided custom CSS selectors
9
+ // /!\ Please do not modify the classnames! This is a breaking change, and annoying for users!
8
10
  export const ThemeClassNames = {
9
11
  page: {
10
12
  blogListPage: 'blog-list-page',
11
13
  blogPostPage: 'blog-post-page',
12
14
  blogTagsListPage: 'blog-tags-list-page',
13
- blogTagsPostPage: 'blog-tags-post-page',
14
- docPage: 'doc-page',
15
+ blogTagPostListPage: 'blog-tags-post-list-page',
16
+ docsDocPage: 'docs-doc-page',
17
+ docsTagsListPage: 'docs-tags-list-page',
18
+ docsTagDocListPage: 'docs-tags-doc-list-page',
15
19
  mdxPage: 'mdx-page',
16
20
  },
17
21
  wrapper: {
18
22
  main: 'main-wrapper',
19
23
  blogPages: 'blog-wrapper',
20
- docPages: 'docs-wrapper',
24
+ docsPages: 'docs-wrapper',
21
25
  mdxPages: 'mdx-wrapper',
22
26
  },
27
+ // /!\ Please keep the naming convention consistent!
28
+ // Something like: "theme-{blog,doc,version,page}?-<suffix>"
29
+ common: {
30
+ editThisPage: 'theme-edit-this-page',
31
+ lastUpdated: 'theme-last-updated',
32
+ backToTopButton: 'theme-back-to-top-button',
33
+ },
34
+ layout: {
35
+ // TODO add other stable classNames here
36
+ },
37
+ docs: {
38
+ docVersionBanner: 'theme-doc-version-banner',
39
+ docVersionBadge: 'theme-doc-version-badge',
40
+ docMarkdown: 'theme-doc-markdown',
41
+ docTocMobile: 'theme-doc-toc-mobile',
42
+ docTocDesktop: 'theme-doc-toc-desktop',
43
+ docFooter: 'theme-doc-footer',
44
+ docFooterTagsRow: 'theme-doc-footer-tags-row',
45
+ docFooterEditMetaRow: 'theme-doc-footer-edit-meta-row',
46
+ docSidebarMenu: 'theme-doc-sidebar-menu',
47
+ docSidebarItemCategory: 'theme-doc-sidebar-item-category',
48
+ docSidebarItemLink: 'theme-doc-sidebar-item-link',
49
+ docSidebarItemCategoryLevel: (level) => `theme-doc-sidebar-item-category-level-${level}`,
50
+ docSidebarItemLinkLevel: (level) => `theme-doc-sidebar-item-link-level-${level}`,
51
+ // TODO add other stable classNames here
52
+ },
53
+ blog: {
54
+ // TODO add other stable classNames here
55
+ },
23
56
  };
@@ -0,0 +1,17 @@
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 { ReactNode } from 'react';
8
+ export declare const AnnouncementBarDismissStorageKey = "docusaurus.announcement.dismiss";
9
+ declare type AnnouncementBarAPI = {
10
+ readonly isActive: boolean;
11
+ readonly close: () => void;
12
+ };
13
+ export declare const AnnouncementBarProvider: ({ children, }: {
14
+ children: ReactNode;
15
+ }) => JSX.Element;
16
+ export declare const useAnnouncementBar: () => AnnouncementBarAPI;
17
+ export {};
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React, { useState, useEffect, useCallback, useMemo, useContext, createContext, } from 'react';
8
+ import useIsBrowser from '@docusaurus/useIsBrowser';
9
+ import { createStorageSlot } from './storageUtils';
10
+ import { useThemeConfig } from './useThemeConfig';
11
+ export const AnnouncementBarDismissStorageKey = 'docusaurus.announcement.dismiss';
12
+ const AnnouncementBarIdStorageKey = 'docusaurus.announcement.id';
13
+ const AnnouncementBarDismissStorage = createStorageSlot(AnnouncementBarDismissStorageKey);
14
+ const IdStorage = createStorageSlot(AnnouncementBarIdStorageKey);
15
+ const isDismissedInStorage = () => AnnouncementBarDismissStorage.get() === 'true';
16
+ const setDismissedInStorage = (bool) => AnnouncementBarDismissStorage.set(String(bool));
17
+ const useAnnouncementBarContextValue = () => {
18
+ const { announcementBar } = useThemeConfig();
19
+ const isBrowser = useIsBrowser();
20
+ const [isClosed, setClosed] = useState(() => {
21
+ return isBrowser
22
+ ? // On client navigation: init with localstorage value
23
+ isDismissedInStorage()
24
+ : // On server/hydration: always visible to prevent layout shifts (will be hidden with css if needed)
25
+ false;
26
+ });
27
+ // Update state after hydration
28
+ useEffect(() => {
29
+ setClosed(isDismissedInStorage());
30
+ }, []);
31
+ const handleClose = useCallback(() => {
32
+ setDismissedInStorage(true);
33
+ setClosed(true);
34
+ }, []);
35
+ useEffect(() => {
36
+ if (!announcementBar) {
37
+ return;
38
+ }
39
+ const { id } = announcementBar;
40
+ let viewedId = IdStorage.get();
41
+ // retrocompatibility due to spelling mistake of default id
42
+ // see https://github.com/facebook/docusaurus/issues/3338
43
+ if (viewedId === 'annoucement-bar') {
44
+ viewedId = 'announcement-bar';
45
+ }
46
+ const isNewAnnouncement = id !== viewedId;
47
+ IdStorage.set(id);
48
+ if (isNewAnnouncement) {
49
+ setDismissedInStorage(false);
50
+ }
51
+ if (isNewAnnouncement || !isDismissedInStorage()) {
52
+ setClosed(false);
53
+ }
54
+ }, [announcementBar]);
55
+ return useMemo(() => {
56
+ return {
57
+ isActive: !!announcementBar && !isClosed,
58
+ close: handleClose,
59
+ };
60
+ }, [announcementBar, isClosed, handleClose]);
61
+ };
62
+ const AnnouncementBarContext = createContext(null);
63
+ export const AnnouncementBarProvider = ({ children, }) => {
64
+ const value = useAnnouncementBarContextValue();
65
+ return (React.createElement(AnnouncementBarContext.Provider, { value: value }, children));
66
+ };
67
+ export const useAnnouncementBar = () => {
68
+ const api = useContext(AnnouncementBarContext);
69
+ if (!api) {
70
+ throw new Error('useAnnouncementBar(): AnnouncementBar not found in React context: make sure to use the AnnouncementBarProvider on top of the tree');
71
+ }
72
+ return api;
73
+ };
@@ -69,7 +69,7 @@ function useContextValue() {
69
69
  return {
70
70
  savePreferredVersion,
71
71
  };
72
- }, [setState]);
72
+ }, [versionPersistence]);
73
73
  return [state, api];
74
74
  }
75
75
  const Context = createContext(null);
@@ -1,5 +1,7 @@
1
+ /// <reference types="@docusaurus/plugin-content-docs" />
2
+ import { GlobalVersion } from '@theme/hooks/useDocs';
1
3
  export declare function useDocsPreferredVersion(pluginId?: string | undefined): {
2
- readonly preferredVersion: any;
3
- readonly savePreferredVersionName: (versionName: string) => void;
4
+ preferredVersion: GlobalVersion | null | undefined;
5
+ savePreferredVersionName: (versionName: string) => void;
4
6
  };
5
- export declare function useDocsPreferredVersionByPluginId(): Record<string, any>;
7
+ export declare function useDocsPreferredVersionByPluginId(): Record<string, GlobalVersion | null | undefined>;
@@ -8,7 +8,6 @@ import { useCallback } from 'react';
8
8
  import { useDocsPreferredVersionContext } from './DocsPreferredVersionProvider';
9
9
  import { useAllDocsData, useDocsData } from '@theme/hooks/useDocs';
10
10
  import { DEFAULT_PLUGIN_ID } from '@docusaurus/constants';
11
- // TODO improve typing
12
11
  // Note, the preferredVersion attribute will always be null before mount
13
12
  export function useDocsPreferredVersion(pluginId = DEFAULT_PLUGIN_ID) {
14
13
  const docsData = useDocsData(pluginId);
@@ -19,7 +18,7 @@ export function useDocsPreferredVersion(pluginId = DEFAULT_PLUGIN_ID) {
19
18
  : null;
20
19
  const savePreferredVersionName = useCallback((versionName) => {
21
20
  api.savePreferredVersion(pluginId, versionName);
22
- }, [api]);
21
+ }, [api, pluginId]);
23
22
  return { preferredVersion, savePreferredVersionName };
24
23
  }
25
24
  export function useDocsPreferredVersionByPluginId() {
@@ -6,8 +6,8 @@
6
6
  */
7
7
  import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
8
8
  export const useTitleFormatter = (title) => {
9
- const { siteConfig = {} } = useDocusaurusContext();
10
- const { title: siteTitle, titleDelimiter = '|' } = siteConfig;
9
+ const { siteConfig } = useDocusaurusContext();
10
+ const { title: siteTitle, titleDelimiter } = siteConfig;
11
11
  return title && title.trim().length
12
12
  ? `${title.trim()} ${titleDelimiter} ${siteTitle}`
13
13
  : siteTitle;
@@ -0,0 +1,11 @@
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 { Location, Action } from '@docusaurus/history';
8
+ declare type HistoryBlockHandler = (location: Location, action: Action) => void | false;
9
+ export declare function useHistoryActionHandler(handler: HistoryBlockHandler): void;
10
+ export declare function useHistoryPopHandler(handler: HistoryBlockHandler): void;
11
+ export {};
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { useEffect, useRef } from 'react';
8
+ import { useHistory } from '@docusaurus/router';
9
+ /*
10
+ Permits to register a handler that will be called on history actions (pop,push,replace)
11
+ If the handler returns false, the navigation transition will be blocked/cancelled
12
+ */
13
+ export function useHistoryActionHandler(handler) {
14
+ const { block } = useHistory();
15
+ // Avoid stale closure issues without triggering useless re-renders
16
+ const lastHandlerRef = useRef(handler);
17
+ useEffect(() => {
18
+ lastHandlerRef.current = handler;
19
+ }, [handler]);
20
+ useEffect(() => {
21
+ // See https://github.com/remix-run/history/blob/main/docs/blocking-transitions.md
22
+ return block((location, action) => {
23
+ return lastHandlerRef.current(location, action);
24
+ });
25
+ }, [block, lastHandlerRef]);
26
+ }
27
+ /*
28
+ Permits to register a handler that will be called on history pop navigation (backward/forward)
29
+ If the handler returns false, the backward/forward transition will be blocked
30
+
31
+ Unfortunately there's no good way to detect the "direction" (backward/forward) of the POP event.
32
+ */
33
+ export function useHistoryPopHandler(handler) {
34
+ useHistoryActionHandler((location, action) => {
35
+ if (action === 'POP') {
36
+ // Eventually block navigation if handler returns false
37
+ return handler(location, action);
38
+ }
39
+ // Don't block other navigation actions
40
+ return undefined;
41
+ });
42
+ }
@@ -0,0 +1,13 @@
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
+ * Gets the duplicate values in an array.
9
+ * @param arr The array.
10
+ * @param comparator Compares two values and returns `true` if they are equal (duplicated).
11
+ * @returns Value of the elements `v` that have a preceding element `u` where `comparator(u, v) === true`. Values within the returned array are not guaranteed to be unique.
12
+ */
13
+ export declare function duplicates<T>(arr: readonly T[], comparator?: (a: T, b: T) => boolean): T[];
@@ -0,0 +1,16 @@
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
+ // A replacement of lodash in client code
8
+ /**
9
+ * Gets the duplicate values in an array.
10
+ * @param arr The array.
11
+ * @param comparator Compares two values and returns `true` if they are equal (duplicated).
12
+ * @returns Value of the elements `v` that have a preceding element `u` where `comparator(u, v) === true`. Values within the returned array are not guaranteed to be unique.
13
+ */
14
+ export function duplicates(arr, comparator = (a, b) => a === b) {
15
+ return arr.filter((v, vIndex) => arr.findIndex((u) => comparator(u, v)) !== vIndex);
16
+ }
@@ -0,0 +1,20 @@
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 { ReactNode, ComponentType } from 'react';
8
+ declare type ExtraProps = {
9
+ toggleSidebar: () => void;
10
+ };
11
+ export declare type MobileSecondaryMenuComponent<Props extends unknown> = ComponentType<Props & ExtraProps>;
12
+ export declare function MobileSecondaryMenuProvider({ children, }: {
13
+ children: ReactNode;
14
+ }): JSX.Element;
15
+ export declare function useMobileSecondaryMenuRenderer(): (extraProps: ExtraProps) => ReactNode | undefined;
16
+ export declare function MobileSecondaryMenuFiller<Props extends Record<string, unknown>>({ component, props, }: {
17
+ component: MobileSecondaryMenuComponent<Props & ExtraProps>;
18
+ props: Props;
19
+ }): JSX.Element | null;
20
+ export {};
@@ -0,0 +1,51 @@
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, { useState, useContext, createContext, useEffect, useMemo, } from 'react';
8
+ function useContextValue() {
9
+ return useState(null);
10
+ }
11
+ const Context = createContext(null);
12
+ export function MobileSecondaryMenuProvider({ children, }) {
13
+ return (React.createElement(Context.Provider, { value: useContextValue() }, children));
14
+ }
15
+ function useMobileSecondaryMenuContext() {
16
+ const value = useContext(Context);
17
+ if (value === null) {
18
+ throw new Error('MobileSecondaryMenuProvider was not used correctly, context value is null');
19
+ }
20
+ return value;
21
+ }
22
+ export function useMobileSecondaryMenuRenderer() {
23
+ const [state] = useMobileSecondaryMenuContext();
24
+ if (state) {
25
+ const Comp = state.component;
26
+ return function render(extraProps) {
27
+ return React.createElement(Comp, { ...state.props, ...extraProps });
28
+ };
29
+ }
30
+ return () => undefined;
31
+ }
32
+ function useShallowMemoizedObject(obj) {
33
+ return useMemo(() => obj,
34
+ // Is this safe?
35
+ // eslint-disable-next-line react-hooks/exhaustive-deps
36
+ [...Object.keys(obj), ...Object.values(obj)]);
37
+ }
38
+ // Fill the secondary menu placeholder with some real content
39
+ export function MobileSecondaryMenuFiller({ component, props, }) {
40
+ const [, setState] = useMobileSecondaryMenuContext();
41
+ // To avoid useless context re-renders, props are memoized shallowly
42
+ const memoizedProps = useShallowMemoizedObject(props);
43
+ useEffect(() => {
44
+ // @ts-expect-error: context is not 100% typesafe but it's ok
45
+ setState({ component, props: memoizedProps });
46
+ }, [setState, component, memoizedProps]);
47
+ useEffect(() => {
48
+ return () => setState(null);
49
+ }, [setState]);
50
+ return null;
51
+ }
@@ -0,0 +1,9 @@
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 { useLayoutEffect } from 'react';
8
+ export declare const useIsomorphicLayoutEffect: typeof useLayoutEffect;
9
+ export declare function useDynamicCallback<T extends (...args: never[]) => unknown>(callback: T): T;
@@ -0,0 +1,26 @@
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 { useCallback, useEffect, useLayoutEffect, useRef } from 'react';
8
+ // This hook is like useLayoutEffect, but without the SSR warning
9
+ // It seems hacky but it's used in many React libs (Redux, Formik...)
10
+ // Also mentioned here: https://github.com/facebook/react/issues/16956
11
+ // It is useful when you need to update a ref as soon as possible after a React render (before useEffect)
12
+ export const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
13
+ // Permits to transform an unstable callback (like an arrow function provided as props)
14
+ // to a "stable" callback that is safe to use in a useEffect dependency array
15
+ // Useful to avoid React stale closure problems + avoid useless effect re-executions
16
+ //
17
+ // Workaround until the React team recommends a good solution, see https://github.com/facebook/react/issues/16956
18
+ // This generally works has some potential drawbacks, such as https://github.com/facebook/react/issues/16956#issuecomment-536636418
19
+ export function useDynamicCallback(callback) {
20
+ const ref = useRef(callback);
21
+ useIsomorphicLayoutEffect(() => {
22
+ ref.current = callback;
23
+ }, [callback]);
24
+ // @ts-expect-error: TODO, not sure how to fix this TS error
25
+ return useCallback((...args) => ref.current(...args), []);
26
+ }
@@ -0,0 +1,10 @@
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
+ * Utility to convert an optional string into a Regex case sensitive and global
9
+ */
10
+ export declare function isRegexpStringMatch(regexAsString?: string, valueToTest?: string): boolean;