@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.
- package/copyUntypedFiles.js +20 -0
- package/lib/.tsbuildinfo +1 -1
- package/lib/components/Collapsible/index.d.ts +35 -0
- package/lib/components/Collapsible/index.js +139 -0
- package/lib/components/Details/index.d.ts +12 -0
- package/lib/components/Details/index.js +64 -0
- package/lib/components/Details/styles.module.css +58 -0
- package/lib/index.d.ts +19 -1
- package/lib/index.js +13 -0
- package/lib/utils/ThemeClassNames.d.ts +36 -12
- package/lib/utils/ThemeClassNames.js +36 -3
- package/lib/utils/announcementBarUtils.d.ts +17 -0
- package/lib/utils/announcementBarUtils.js +73 -0
- package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.js +1 -1
- package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.d.ts +5 -3
- package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.js +1 -2
- package/lib/utils/generalUtils.js +2 -2
- package/lib/utils/historyUtils.d.ts +11 -0
- package/lib/utils/historyUtils.js +42 -0
- package/lib/utils/jsUtils.d.ts +13 -0
- package/lib/utils/jsUtils.js +16 -0
- package/lib/utils/mobileSecondaryMenu.d.ts +20 -0
- package/lib/utils/mobileSecondaryMenu.js +51 -0
- package/lib/utils/reactUtils.d.ts +9 -0
- package/lib/utils/reactUtils.js +26 -0
- package/lib/utils/regexpUtils.d.ts +10 -0
- package/lib/utils/regexpUtils.js +16 -0
- package/lib/utils/scrollUtils.d.ts +52 -0
- package/lib/utils/scrollUtils.js +137 -0
- package/lib/utils/tagsUtils.d.ts +18 -0
- package/lib/utils/tagsUtils.js +33 -0
- package/lib/utils/tocUtils.d.ts +15 -0
- package/lib/utils/tocUtils.js +36 -0
- package/lib/utils/useLocalPathname.d.ts +7 -0
- package/lib/utils/useLocalPathname.js +16 -0
- package/lib/utils/useLocationChange.js +5 -9
- package/lib/utils/usePrevious.js +3 -2
- package/lib/utils/useTOCHighlight.d.ts +14 -0
- package/lib/utils/useTOCHighlight.js +124 -0
- package/lib/utils/useThemeConfig.d.ts +14 -2
- package/package.json +16 -12
- package/src/components/Collapsible/index.tsx +242 -0
- package/src/components/Details/index.tsx +94 -0
- package/src/components/Details/styles.module.css +58 -0
- package/src/index.ts +50 -0
- package/src/types.d.ts +0 -2
- package/src/utils/ThemeClassNames.ts +42 -4
- package/src/utils/__tests__/tagUtils.test.ts +66 -0
- package/src/utils/__tests__/tocUtils.test.ts +197 -0
- package/src/utils/announcementBarUtils.tsx +119 -0
- package/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx +4 -4
- package/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts +13 -14
- package/src/utils/generalUtils.ts +2 -2
- package/src/utils/historyUtils.ts +50 -0
- package/src/utils/jsUtils.ts +23 -0
- package/src/utils/mobileSecondaryMenu.tsx +116 -0
- package/src/utils/reactUtils.tsx +34 -0
- package/src/utils/regexpUtils.ts +23 -0
- package/src/utils/scrollUtils.tsx +238 -0
- package/src/utils/storageUtils.ts +1 -1
- package/src/utils/tagsUtils.ts +48 -0
- package/src/utils/tocUtils.ts +54 -0
- package/src/utils/useAlternatePageUtils.ts +9 -1
- package/src/utils/useLocalPathname.ts +20 -0
- package/src/utils/useLocationChange.ts +6 -10
- package/src/utils/usePluralForm.ts +3 -1
- package/src/utils/usePrevious.ts +3 -2
- package/src/utils/useTOCHighlight.ts +179 -0
- 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:
|
|
10
|
-
blogPostPage:
|
|
11
|
-
blogTagsListPage:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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:
|
|
18
|
-
blogPages:
|
|
19
|
-
|
|
20
|
-
mdxPages:
|
|
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
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
+
};
|
|
@@ -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
|
-
|
|
3
|
-
|
|
4
|
+
preferredVersion: GlobalVersion | null | undefined;
|
|
5
|
+
savePreferredVersionName: (versionName: string) => void;
|
|
4
6
|
};
|
|
5
|
-
export declare function useDocsPreferredVersionByPluginId(): Record<string,
|
|
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
|
|
10
|
-
const { title: siteTitle, titleDelimiter
|
|
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;
|