@docusaurus/theme-common 2.0.0-beta.12faed89d → 2.0.0-beta.13
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/{utils/useCollapsible.d.ts → components/Collapsible/index.d.ts} +9 -3
- package/lib/{utils/useCollapsible.js → components/Collapsible/index.js} +36 -14
- 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 -5
- package/lib/index.js +14 -3
- package/lib/utils/ThemeClassNames.d.ts +36 -12
- package/lib/utils/ThemeClassNames.js +36 -3
- package/lib/utils/announcementBarUtils.d.ts +3 -3
- package/lib/utils/announcementBarUtils.js +14 -18
- package/lib/utils/codeBlockUtils.d.ts +10 -0
- package/lib/utils/codeBlockUtils.js +119 -0
- package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.d.ts +2 -2
- package/lib/utils/docsPreferredVersion/DocsPreferredVersionProvider.js +2 -2
- package/lib/utils/docsPreferredVersion/DocsPreferredVersionStorage.js +1 -3
- package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.d.ts +11 -3
- package/lib/utils/docsPreferredVersion/useDocsPreferredVersion.js +1 -2
- package/lib/utils/docsUtils.d.ts +20 -0
- package/lib/utils/docsUtils.js +106 -0
- package/lib/utils/generalUtils.d.ts +6 -0
- package/lib/utils/generalUtils.js +2 -2
- package/lib/utils/historyUtils.d.ts +11 -0
- package/lib/utils/historyUtils.js +39 -0
- package/lib/utils/jsUtils.d.ts +19 -0
- package/lib/utils/jsUtils.js +25 -0
- package/lib/utils/mobileSecondaryMenu.d.ts +2 -2
- package/lib/utils/mobileSecondaryMenu.js +3 -4
- package/lib/utils/pathUtils.js +1 -3
- 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 +135 -0
- package/lib/utils/storageUtils.d.ts +4 -0
- package/lib/utils/storageUtils.js +29 -3
- 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 +34 -0
- package/lib/utils/useContextualSearchFilters.d.ts +11 -0
- package/lib/utils/useContextualSearchFilters.js +36 -0
- package/{src/utils/docsUtils.ts → lib/utils/useLocalPathname.d.ts} +1 -5
- package/lib/utils/useLocalPathname.js +16 -0
- package/lib/utils/useLocationChange.js +9 -11
- package/lib/utils/usePluralForm.js +1 -3
- 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 +20 -3
- package/package.json +18 -12
- package/src/{utils/useCollapsible.tsx → components/Collapsible/index.tsx} +70 -25
- package/src/components/Details/index.tsx +94 -0
- package/src/components/Details/styles.module.css +58 -0
- package/src/index.ts +54 -4
- package/src/types.d.ts +0 -2
- package/src/utils/ThemeClassNames.ts +42 -4
- package/src/utils/__tests__/codeBlockUtils.test.ts +2 -2
- package/src/utils/__tests__/docsUtils.test.tsx +331 -0
- package/src/utils/__tests__/jsUtils.test.ts +33 -0
- package/src/utils/__tests__/tagUtils.test.ts +66 -0
- package/src/utils/__tests__/tocUtils.test.ts +197 -0
- package/src/utils/announcementBarUtils.tsx +20 -15
- package/src/utils/codeBlockUtils.ts +151 -0
- package/src/utils/docsPreferredVersion/DocsPreferredVersionProvider.tsx +7 -6
- package/src/utils/docsPreferredVersion/DocsPreferredVersionStorage.ts +2 -3
- package/src/utils/docsPreferredVersion/useDocsPreferredVersion.ts +14 -14
- package/src/utils/docsUtils.tsx +185 -0
- package/src/utils/generalUtils.ts +3 -2
- package/src/utils/historyUtils.ts +50 -0
- package/src/utils/jsUtils.ts +33 -0
- package/src/utils/mobileSecondaryMenu.tsx +9 -6
- package/src/utils/pathUtils.ts +2 -3
- package/src/utils/reactUtils.tsx +34 -0
- package/src/utils/regexpUtils.ts +23 -0
- package/src/utils/scrollUtils.tsx +237 -0
- package/src/utils/storageUtils.ts +27 -4
- package/src/utils/tagsUtils.ts +48 -0
- package/src/utils/tocUtils.ts +55 -0
- package/src/utils/useContextualSearchFilters.ts +50 -0
- package/src/utils/useLocalPathname.ts +20 -0
- package/src/utils/useLocationChange.ts +10 -12
- package/src/utils/usePluralForm.ts +2 -3
- package/src/utils/usePrevious.ts +3 -2
- package/src/utils/useTOCHighlight.ts +179 -0
- package/src/utils/useThemeConfig.ts +19 -3
|
@@ -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/src/index.ts
CHANGED
|
@@ -9,23 +9,42 @@ export {useThemeConfig} from './utils/useThemeConfig';
|
|
|
9
9
|
|
|
10
10
|
export type {
|
|
11
11
|
ThemeConfig,
|
|
12
|
+
UserThemeConfig,
|
|
12
13
|
Navbar,
|
|
13
14
|
NavbarItem,
|
|
14
15
|
NavbarLogo,
|
|
15
16
|
Footer,
|
|
16
17
|
FooterLinks,
|
|
17
18
|
FooterLinkItem,
|
|
19
|
+
ColorModeConfig,
|
|
18
20
|
} from './utils/useThemeConfig';
|
|
19
21
|
|
|
20
22
|
export {createStorageSlot, listStorageKeys} from './utils/storageUtils';
|
|
21
23
|
|
|
22
24
|
export {useAlternatePageUtils} from './utils/useAlternatePageUtils';
|
|
23
25
|
|
|
24
|
-
export {
|
|
26
|
+
export {useContextualSearchFilters} from './utils/useContextualSearchFilters';
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
parseCodeBlockTitle,
|
|
30
|
+
parseLanguage,
|
|
31
|
+
parseLines,
|
|
32
|
+
} from './utils/codeBlockUtils';
|
|
25
33
|
|
|
26
34
|
export {docVersionSearchTag, DEFAULT_SEARCH_TAG} from './utils/searchUtils';
|
|
27
35
|
|
|
28
|
-
export {
|
|
36
|
+
export {
|
|
37
|
+
isDocsPluginEnabled,
|
|
38
|
+
DocsVersionProvider,
|
|
39
|
+
useDocsVersion,
|
|
40
|
+
useDocById,
|
|
41
|
+
DocsSidebarProvider,
|
|
42
|
+
useDocsSidebar,
|
|
43
|
+
findSidebarCategory,
|
|
44
|
+
findFirstCategoryLink,
|
|
45
|
+
useCurrentSidebarCategory,
|
|
46
|
+
isActiveSidebarItem,
|
|
47
|
+
} from './utils/docsUtils';
|
|
29
48
|
|
|
30
49
|
export {isSamePath} from './utils/pathUtils';
|
|
31
50
|
|
|
@@ -37,11 +56,14 @@ export {useLocationChange} from './utils/useLocationChange';
|
|
|
37
56
|
|
|
38
57
|
export {usePrevious} from './utils/usePrevious';
|
|
39
58
|
|
|
40
|
-
export {useCollapsible, Collapsible} from './
|
|
59
|
+
export {useCollapsible, Collapsible} from './components/Collapsible';
|
|
41
60
|
export type {
|
|
42
61
|
UseCollapsibleConfig,
|
|
43
62
|
UseCollapsibleReturns,
|
|
44
|
-
} from './
|
|
63
|
+
} from './components/Collapsible';
|
|
64
|
+
|
|
65
|
+
export {default as Details} from './components/Details';
|
|
66
|
+
export type {DetailsProps} from './components/Details';
|
|
45
67
|
|
|
46
68
|
export {
|
|
47
69
|
MobileSecondaryMenuProvider,
|
|
@@ -55,6 +77,8 @@ export {
|
|
|
55
77
|
useDocsPreferredVersionByPluginId,
|
|
56
78
|
} from './utils/docsPreferredVersion/useDocsPreferredVersion';
|
|
57
79
|
|
|
80
|
+
export {duplicates, uniq} from './utils/jsUtils';
|
|
81
|
+
|
|
58
82
|
export {DocsPreferredVersionContextProvider} from './utils/docsPreferredVersion/DocsPreferredVersionProvider';
|
|
59
83
|
|
|
60
84
|
export {ThemeClassNames} from './utils/ThemeClassNames';
|
|
@@ -63,3 +87,29 @@ export {
|
|
|
63
87
|
AnnouncementBarProvider,
|
|
64
88
|
useAnnouncementBar,
|
|
65
89
|
} from './utils/announcementBarUtils';
|
|
90
|
+
|
|
91
|
+
export {useLocalPathname} from './utils/useLocalPathname';
|
|
92
|
+
|
|
93
|
+
export {translateTagsPageTitle, listTagsByLetters} from './utils/tagsUtils';
|
|
94
|
+
export type {TagLetterEntry} from './utils/tagsUtils';
|
|
95
|
+
|
|
96
|
+
export {useHistoryPopHandler} from './utils/historyUtils';
|
|
97
|
+
|
|
98
|
+
export {default as useTOCHighlight} from './utils/useTOCHighlight';
|
|
99
|
+
export type {TOCHighlightConfig} from './utils/useTOCHighlight';
|
|
100
|
+
|
|
101
|
+
export {useTOCFilter} from './utils/tocUtils';
|
|
102
|
+
|
|
103
|
+
export {
|
|
104
|
+
ScrollControllerProvider,
|
|
105
|
+
useScrollController,
|
|
106
|
+
useScrollPosition,
|
|
107
|
+
useScrollPositionBlocker,
|
|
108
|
+
} from './utils/scrollUtils';
|
|
109
|
+
|
|
110
|
+
export {
|
|
111
|
+
useIsomorphicLayoutEffect,
|
|
112
|
+
useDynamicCallback,
|
|
113
|
+
} from './utils/reactUtils';
|
|
114
|
+
|
|
115
|
+
export {isRegexpStringMatch} from './utils/regexpUtils';
|
package/src/types.d.ts
CHANGED
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
/* eslint-disable import/no-duplicates */
|
|
9
|
-
/* eslint-disable spaced-comment */
|
|
10
8
|
/// <reference types="@docusaurus/module-type-aliases" />
|
|
11
9
|
/// <reference types="@docusaurus/plugin-content-blog" />
|
|
12
10
|
/// <reference types="@docusaurus/plugin-content-docs" />
|
|
@@ -6,19 +6,57 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
// These class names are used to style page layouts in Docusaurus
|
|
9
|
+
// Those are meant to be targeted by user-provided custom CSS selectors
|
|
10
|
+
// /!\ Please do not modify the classnames! This is a breaking change, and annoying for users!
|
|
9
11
|
export const ThemeClassNames = {
|
|
10
12
|
page: {
|
|
11
13
|
blogListPage: 'blog-list-page',
|
|
12
14
|
blogPostPage: 'blog-post-page',
|
|
13
15
|
blogTagsListPage: 'blog-tags-list-page',
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
blogTagPostListPage: 'blog-tags-post-list-page',
|
|
17
|
+
|
|
18
|
+
docsDocPage: 'docs-doc-page',
|
|
19
|
+
docsTagsListPage: 'docs-tags-list-page', // List of tags
|
|
20
|
+
docsTagDocListPage: 'docs-tags-doc-list-page', // Docs for a tag
|
|
21
|
+
|
|
16
22
|
mdxPage: 'mdx-page',
|
|
17
23
|
},
|
|
18
24
|
wrapper: {
|
|
19
25
|
main: 'main-wrapper',
|
|
20
26
|
blogPages: 'blog-wrapper',
|
|
21
|
-
|
|
27
|
+
docsPages: 'docs-wrapper',
|
|
22
28
|
mdxPages: 'mdx-wrapper',
|
|
23
29
|
},
|
|
24
|
-
|
|
30
|
+
|
|
31
|
+
// /!\ Please keep the naming convention consistent!
|
|
32
|
+
// Something like: "theme-{blog,doc,version,page}?-<suffix>"
|
|
33
|
+
common: {
|
|
34
|
+
editThisPage: 'theme-edit-this-page',
|
|
35
|
+
lastUpdated: 'theme-last-updated',
|
|
36
|
+
backToTopButton: 'theme-back-to-top-button',
|
|
37
|
+
},
|
|
38
|
+
layout: {
|
|
39
|
+
// TODO add other stable classNames here
|
|
40
|
+
},
|
|
41
|
+
docs: {
|
|
42
|
+
docVersionBanner: 'theme-doc-version-banner',
|
|
43
|
+
docVersionBadge: 'theme-doc-version-badge',
|
|
44
|
+
docMarkdown: 'theme-doc-markdown',
|
|
45
|
+
docTocMobile: 'theme-doc-toc-mobile',
|
|
46
|
+
docTocDesktop: 'theme-doc-toc-desktop',
|
|
47
|
+
docFooter: 'theme-doc-footer',
|
|
48
|
+
docFooterTagsRow: 'theme-doc-footer-tags-row',
|
|
49
|
+
docFooterEditMetaRow: 'theme-doc-footer-edit-meta-row',
|
|
50
|
+
docSidebarMenu: 'theme-doc-sidebar-menu',
|
|
51
|
+
docSidebarItemCategory: 'theme-doc-sidebar-item-category',
|
|
52
|
+
docSidebarItemLink: 'theme-doc-sidebar-item-link',
|
|
53
|
+
docSidebarItemCategoryLevel: (level: number) =>
|
|
54
|
+
`theme-doc-sidebar-item-category-level-${level}` as const,
|
|
55
|
+
docSidebarItemLinkLevel: (level: number) =>
|
|
56
|
+
`theme-doc-sidebar-item-link-level-${level}` as const,
|
|
57
|
+
// TODO add other stable classNames here
|
|
58
|
+
},
|
|
59
|
+
blog: {
|
|
60
|
+
// TODO add other stable classNames here
|
|
61
|
+
},
|
|
62
|
+
} as const;
|
|
@@ -28,13 +28,13 @@ describe('parseCodeBlockTitle', () => {
|
|
|
28
28
|
expect(parseCodeBlockTitle(`{1,2-3}`)).toEqual(``);
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
test('should parse with multiple
|
|
31
|
+
test('should parse with multiple metadata title first', () => {
|
|
32
32
|
expect(parseCodeBlockTitle(`title="index.js" label="JavaScript"`)).toEqual(
|
|
33
33
|
`index.js`,
|
|
34
34
|
);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
test('should parse with multiple
|
|
37
|
+
test('should parse with multiple metadata title last', () => {
|
|
38
38
|
expect(parseCodeBlockTitle(`label="JavaScript" title="index.js"`)).toEqual(
|
|
39
39
|
`index.js`,
|
|
40
40
|
);
|
|
@@ -0,0 +1,331 @@
|
|
|
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 from 'react';
|
|
9
|
+
import {renderHook} from '@testing-library/react-hooks';
|
|
10
|
+
import {
|
|
11
|
+
findFirstCategoryLink,
|
|
12
|
+
isActiveSidebarItem,
|
|
13
|
+
DocsVersionProvider,
|
|
14
|
+
useDocsVersion,
|
|
15
|
+
useDocById,
|
|
16
|
+
useDocsSidebar,
|
|
17
|
+
DocsSidebarProvider,
|
|
18
|
+
findSidebarCategory,
|
|
19
|
+
} from '../docsUtils';
|
|
20
|
+
import {
|
|
21
|
+
PropSidebar,
|
|
22
|
+
PropSidebarItem,
|
|
23
|
+
PropSidebarItemCategory,
|
|
24
|
+
PropVersionMetadata,
|
|
25
|
+
} from '@docusaurus/plugin-content-docs';
|
|
26
|
+
|
|
27
|
+
// Make tests more readable with some useful category item defaults
|
|
28
|
+
function testCategory(
|
|
29
|
+
data?: Partial<PropSidebarItemCategory>,
|
|
30
|
+
): PropSidebarItemCategory {
|
|
31
|
+
return {
|
|
32
|
+
type: 'category',
|
|
33
|
+
href: undefined,
|
|
34
|
+
label: 'Category label',
|
|
35
|
+
items: [],
|
|
36
|
+
collapsed: true,
|
|
37
|
+
collapsible: true,
|
|
38
|
+
...data,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function testVersion(data?: Partial<PropVersionMetadata>): PropVersionMetadata {
|
|
43
|
+
return {
|
|
44
|
+
version: 'versionName',
|
|
45
|
+
label: 'Version Label',
|
|
46
|
+
className: 'version className',
|
|
47
|
+
badge: true,
|
|
48
|
+
banner: 'unreleased',
|
|
49
|
+
docs: {},
|
|
50
|
+
docsSidebars: {},
|
|
51
|
+
isLast: false,
|
|
52
|
+
pluginId: 'default',
|
|
53
|
+
...data,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
describe('docsUtils', () => {
|
|
58
|
+
describe('useDocsVersion', () => {
|
|
59
|
+
test('should throw if context provider is missing', () => {
|
|
60
|
+
expect(
|
|
61
|
+
() => renderHook(() => useDocsVersion()).result.current,
|
|
62
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
63
|
+
`"This hook requires usage of <DocsVersionProvider>"`,
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('should read value from context provider', () => {
|
|
68
|
+
const version = testVersion();
|
|
69
|
+
const {result} = renderHook(() => useDocsVersion(), {
|
|
70
|
+
wrapper: ({children}) => (
|
|
71
|
+
<DocsVersionProvider version={version}>
|
|
72
|
+
{children}
|
|
73
|
+
</DocsVersionProvider>
|
|
74
|
+
),
|
|
75
|
+
});
|
|
76
|
+
expect(result.current).toBe(version);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('useDocsSidebar', () => {
|
|
81
|
+
test('should throw if context provider is missing', () => {
|
|
82
|
+
expect(
|
|
83
|
+
() => renderHook(() => useDocsSidebar()).result.current,
|
|
84
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
85
|
+
`"This hook requires usage of <DocsSidebarProvider>"`,
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('should read value from context provider', () => {
|
|
90
|
+
const sidebar: PropSidebar = [];
|
|
91
|
+
const {result} = renderHook(() => useDocsSidebar(), {
|
|
92
|
+
wrapper: ({children}) => (
|
|
93
|
+
<DocsSidebarProvider sidebar={sidebar}>
|
|
94
|
+
{children}
|
|
95
|
+
</DocsSidebarProvider>
|
|
96
|
+
),
|
|
97
|
+
});
|
|
98
|
+
expect(result.current).toBe(sidebar);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('useDocById', () => {
|
|
103
|
+
const version = testVersion({
|
|
104
|
+
docs: {
|
|
105
|
+
doc1: {
|
|
106
|
+
id: 'doc1',
|
|
107
|
+
title: 'Doc 1',
|
|
108
|
+
description: 'desc1',
|
|
109
|
+
sidebar: 'sidebar1',
|
|
110
|
+
},
|
|
111
|
+
doc2: {
|
|
112
|
+
id: 'doc2',
|
|
113
|
+
title: 'Doc 2',
|
|
114
|
+
description: 'desc2',
|
|
115
|
+
sidebar: 'sidebar2',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
function callHook(docId: string | undefined) {
|
|
121
|
+
const {result} = renderHook(() => useDocById(docId), {
|
|
122
|
+
wrapper: ({children}) => (
|
|
123
|
+
<DocsVersionProvider version={version}>
|
|
124
|
+
{children}
|
|
125
|
+
</DocsVersionProvider>
|
|
126
|
+
),
|
|
127
|
+
});
|
|
128
|
+
return result.current;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
test('should accept undefined', () => {
|
|
132
|
+
expect(callHook(undefined)).toBeUndefined();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('should find doc1', () => {
|
|
136
|
+
expect(callHook('doc1')).toMatchObject({id: 'doc1'});
|
|
137
|
+
});
|
|
138
|
+
test('should find doc2', () => {
|
|
139
|
+
expect(callHook('doc2')).toMatchObject({id: 'doc2'});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('should throw for doc3', () => {
|
|
143
|
+
expect(() => callHook('doc3')).toThrowErrorMatchingInlineSnapshot(
|
|
144
|
+
`"no version doc found by id=doc3"`,
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('findSidebarCategory', () => {
|
|
150
|
+
test('should be able to return undefined', () => {
|
|
151
|
+
expect(findSidebarCategory([], () => false)).toBeUndefined();
|
|
152
|
+
expect(
|
|
153
|
+
findSidebarCategory([testCategory(), testCategory()], () => false),
|
|
154
|
+
).toBeUndefined();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('should return first element matching predicate', () => {
|
|
158
|
+
const first = testCategory();
|
|
159
|
+
const second = testCategory();
|
|
160
|
+
const third = testCategory();
|
|
161
|
+
const sidebar = [first, second, third];
|
|
162
|
+
expect(findSidebarCategory(sidebar, () => true)).toEqual(first);
|
|
163
|
+
expect(findSidebarCategory(sidebar, (item) => item === first)).toEqual(
|
|
164
|
+
first,
|
|
165
|
+
);
|
|
166
|
+
expect(findSidebarCategory(sidebar, (item) => item === second)).toEqual(
|
|
167
|
+
second,
|
|
168
|
+
);
|
|
169
|
+
expect(findSidebarCategory(sidebar, (item) => item === third)).toEqual(
|
|
170
|
+
third,
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('should be able to search in sub items', () => {
|
|
175
|
+
const subsub1 = testCategory();
|
|
176
|
+
const subsub2 = testCategory();
|
|
177
|
+
const sub1 = testCategory({
|
|
178
|
+
items: [subsub1, subsub2],
|
|
179
|
+
});
|
|
180
|
+
const sub2 = testCategory();
|
|
181
|
+
const parent = testCategory({
|
|
182
|
+
items: [sub1, sub2],
|
|
183
|
+
});
|
|
184
|
+
const sidebar = [parent];
|
|
185
|
+
|
|
186
|
+
expect(findSidebarCategory(sidebar, () => true)).toEqual(parent);
|
|
187
|
+
expect(findSidebarCategory(sidebar, (item) => item === sub1)).toEqual(
|
|
188
|
+
sub1,
|
|
189
|
+
);
|
|
190
|
+
expect(findSidebarCategory(sidebar, (item) => item === sub2)).toEqual(
|
|
191
|
+
sub2,
|
|
192
|
+
);
|
|
193
|
+
expect(findSidebarCategory(sidebar, (item) => item === subsub1)).toEqual(
|
|
194
|
+
subsub1,
|
|
195
|
+
);
|
|
196
|
+
expect(findSidebarCategory(sidebar, (item) => item === subsub2)).toEqual(
|
|
197
|
+
subsub2,
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
describe('findFirstCategoryLink', () => {
|
|
203
|
+
test('category without link nor child', () => {
|
|
204
|
+
expect(
|
|
205
|
+
findFirstCategoryLink(
|
|
206
|
+
testCategory({
|
|
207
|
+
href: undefined,
|
|
208
|
+
}),
|
|
209
|
+
),
|
|
210
|
+
).toEqual(undefined);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test('category with link', () => {
|
|
214
|
+
expect(
|
|
215
|
+
findFirstCategoryLink(
|
|
216
|
+
testCategory({
|
|
217
|
+
href: '/itemPath',
|
|
218
|
+
}),
|
|
219
|
+
),
|
|
220
|
+
).toEqual('/itemPath');
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('category with deeply nested category link', () => {
|
|
224
|
+
expect(
|
|
225
|
+
findFirstCategoryLink(
|
|
226
|
+
testCategory({
|
|
227
|
+
href: undefined,
|
|
228
|
+
items: [
|
|
229
|
+
testCategory({
|
|
230
|
+
href: undefined,
|
|
231
|
+
items: [
|
|
232
|
+
testCategory({
|
|
233
|
+
href: '/itemPath',
|
|
234
|
+
}),
|
|
235
|
+
],
|
|
236
|
+
}),
|
|
237
|
+
],
|
|
238
|
+
}),
|
|
239
|
+
),
|
|
240
|
+
).toEqual('/itemPath');
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test('category with deeply nested link', () => {
|
|
244
|
+
expect(
|
|
245
|
+
findFirstCategoryLink(
|
|
246
|
+
testCategory({
|
|
247
|
+
href: undefined,
|
|
248
|
+
items: [
|
|
249
|
+
testCategory({
|
|
250
|
+
href: undefined,
|
|
251
|
+
items: [{type: 'link', href: '/itemPath', label: 'Label'}],
|
|
252
|
+
}),
|
|
253
|
+
],
|
|
254
|
+
}),
|
|
255
|
+
),
|
|
256
|
+
).toEqual('/itemPath');
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
describe('isActiveSidebarItem', () => {
|
|
261
|
+
test('with link href', () => {
|
|
262
|
+
const item: PropSidebarItem = {
|
|
263
|
+
type: 'link',
|
|
264
|
+
href: '/itemPath',
|
|
265
|
+
label: 'Label',
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false);
|
|
269
|
+
|
|
270
|
+
expect(isActiveSidebarItem(item, '/itemPath')).toEqual(true);
|
|
271
|
+
|
|
272
|
+
// Ensure it's not trailing slash sensitive:
|
|
273
|
+
expect(isActiveSidebarItem(item, '/itemPath/')).toEqual(true);
|
|
274
|
+
expect(
|
|
275
|
+
isActiveSidebarItem({...item, href: '/itemPath/'}, '/itemPath'),
|
|
276
|
+
).toEqual(true);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test('with category href', () => {
|
|
280
|
+
const item: PropSidebarItem = testCategory({
|
|
281
|
+
href: '/itemPath',
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false);
|
|
285
|
+
|
|
286
|
+
expect(isActiveSidebarItem(item, '/itemPath')).toEqual(true);
|
|
287
|
+
|
|
288
|
+
// Ensure it's not trailing slash sensitive:
|
|
289
|
+
expect(isActiveSidebarItem(item, '/itemPath/')).toEqual(true);
|
|
290
|
+
expect(
|
|
291
|
+
isActiveSidebarItem({...item, href: '/itemPath/'}, '/itemPath'),
|
|
292
|
+
).toEqual(true);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test('with category nested items', () => {
|
|
296
|
+
const item: PropSidebarItem = testCategory({
|
|
297
|
+
href: '/category-path',
|
|
298
|
+
items: [
|
|
299
|
+
{
|
|
300
|
+
type: 'link',
|
|
301
|
+
href: '/sub-link-path',
|
|
302
|
+
label: 'Label',
|
|
303
|
+
},
|
|
304
|
+
testCategory({
|
|
305
|
+
href: '/sub-category-path',
|
|
306
|
+
items: [
|
|
307
|
+
{
|
|
308
|
+
type: 'link',
|
|
309
|
+
href: '/sub-sub-link-path',
|
|
310
|
+
label: 'Label',
|
|
311
|
+
},
|
|
312
|
+
],
|
|
313
|
+
}),
|
|
314
|
+
],
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
expect(isActiveSidebarItem(item, '/unexistingPath')).toEqual(false);
|
|
318
|
+
|
|
319
|
+
expect(isActiveSidebarItem(item, '/category-path')).toEqual(true);
|
|
320
|
+
expect(isActiveSidebarItem(item, '/sub-link-path')).toEqual(true);
|
|
321
|
+
expect(isActiveSidebarItem(item, '/sub-category-path')).toEqual(true);
|
|
322
|
+
expect(isActiveSidebarItem(item, '/sub-sub-link-path')).toEqual(true);
|
|
323
|
+
|
|
324
|
+
// Ensure it's not trailing slash sensitive:
|
|
325
|
+
expect(isActiveSidebarItem(item, '/category-path/')).toEqual(true);
|
|
326
|
+
expect(isActiveSidebarItem(item, '/sub-link-path/')).toEqual(true);
|
|
327
|
+
expect(isActiveSidebarItem(item, '/sub-category-path/')).toEqual(true);
|
|
328
|
+
expect(isActiveSidebarItem(item, '/sub-sub-link-path/')).toEqual(true);
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
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 {uniq} from '../jsUtils';
|
|
9
|
+
|
|
10
|
+
describe('uniq', () => {
|
|
11
|
+
test('remove duplicate primitives', () => {
|
|
12
|
+
expect(uniq(['A', 'B', 'C', 'B', 'A', 'D'])).toEqual(['A', 'B', 'C', 'D']);
|
|
13
|
+
expect(uniq([3, 3, 5, 1, 6, 3, 5])).toEqual([3, 5, 1, 6]);
|
|
14
|
+
expect(uniq([null, undefined, 3, null, 4, 3])).toEqual([
|
|
15
|
+
null,
|
|
16
|
+
undefined,
|
|
17
|
+
3,
|
|
18
|
+
4,
|
|
19
|
+
]);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('remove duplicate objects/arrays by identity', () => {
|
|
23
|
+
const obj1 = {};
|
|
24
|
+
const obj2 = {};
|
|
25
|
+
const obj3 = {};
|
|
26
|
+
const array1: unknown[] = [];
|
|
27
|
+
const array2: unknown[] = [];
|
|
28
|
+
const array3: unknown[] = [];
|
|
29
|
+
expect(
|
|
30
|
+
uniq([obj1, obj1, obj2, array1, obj2, array3, array2, array1, obj3]),
|
|
31
|
+
).toEqual([obj1, obj2, array1, array3, array2, obj3]);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
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 {shuffle} from 'lodash';
|
|
9
|
+
import {listTagsByLetters} from '../tagsUtils';
|
|
10
|
+
|
|
11
|
+
describe('listTagsByLetters', () => {
|
|
12
|
+
type Param = Parameters<typeof listTagsByLetters>[0];
|
|
13
|
+
type Tag = Param[number];
|
|
14
|
+
type Result = ReturnType<typeof listTagsByLetters>;
|
|
15
|
+
|
|
16
|
+
test('Should create letters list', () => {
|
|
17
|
+
const tag1: Tag = {
|
|
18
|
+
name: 'tag1',
|
|
19
|
+
permalink: '/tag1',
|
|
20
|
+
count: 1,
|
|
21
|
+
};
|
|
22
|
+
const tag2: Tag = {
|
|
23
|
+
name: 'Tag2',
|
|
24
|
+
permalink: '/tag2',
|
|
25
|
+
count: 11,
|
|
26
|
+
};
|
|
27
|
+
const tagzxy: Tag = {
|
|
28
|
+
name: 'zxy',
|
|
29
|
+
permalink: '/zxy',
|
|
30
|
+
count: 987,
|
|
31
|
+
};
|
|
32
|
+
const tagAbc: Tag = {
|
|
33
|
+
name: 'Abc',
|
|
34
|
+
permalink: '/abc',
|
|
35
|
+
count: 123,
|
|
36
|
+
};
|
|
37
|
+
const tagdef: Tag = {
|
|
38
|
+
name: 'def',
|
|
39
|
+
permalink: '/def',
|
|
40
|
+
count: 1,
|
|
41
|
+
};
|
|
42
|
+
const tagaaa: Tag = {
|
|
43
|
+
name: 'aaa',
|
|
44
|
+
permalink: '/aaa',
|
|
45
|
+
count: 10,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const expectedResult: Result = [
|
|
49
|
+
{letter: 'A', tags: [tagaaa, tagAbc]},
|
|
50
|
+
{letter: 'D', tags: [tagdef]},
|
|
51
|
+
{letter: 'T', tags: [tag1, tag2]},
|
|
52
|
+
{letter: 'Z', tags: [tagzxy]},
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
// Input order shouldn't matter, output is always consistently sorted
|
|
56
|
+
expect(
|
|
57
|
+
listTagsByLetters([tag1, tag2, tagzxy, tagAbc, tagdef, tagaaa]),
|
|
58
|
+
).toEqual(expectedResult);
|
|
59
|
+
expect(
|
|
60
|
+
listTagsByLetters([tagzxy, tagdef, tagaaa, tag2, tagAbc, tag1]),
|
|
61
|
+
).toEqual(expectedResult);
|
|
62
|
+
expect(
|
|
63
|
+
listTagsByLetters(shuffle([tagzxy, tagdef, tagaaa, tag2, tagAbc, tag1])),
|
|
64
|
+
).toEqual(expectedResult);
|
|
65
|
+
});
|
|
66
|
+
});
|