docusaurus/packages/docusaurus-plugin-content-docs/src/client/index.ts
Sébastien Lorber 67207bc5e5
fix(theme): Fix <DocCardList> usage on docs at root of a sidebar (#10847)
Fix `<DocCardList>` usage on docs at root of a sidebar
2025-01-16 21:53:41 +01:00

209 lines
5.6 KiB
TypeScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {useLocation} from '@docusaurus/router';
import {
useAllPluginInstancesData,
usePluginData,
} from '@docusaurus/useGlobalData';
import {
getActivePlugin,
getLatestVersion,
getActiveVersion,
getActiveDocContext,
getDocVersionSuggestions,
} from './docsClientUtils';
import type {UseDataOptions} from '@docusaurus/types';
export {
useDocById,
findSidebarCategory,
findFirstSidebarItemLink,
isActiveSidebarItem,
isVisibleSidebarItem,
useVisibleSidebarItems,
useSidebarBreadcrumbs,
useDocsVersionCandidates,
useLayoutDoc,
useLayoutDocsSidebar,
useDocRootMetadata,
useCurrentSidebarCategory,
useCurrentSidebarSiblings,
filterDocCardListItems,
} from './docsUtils';
export {useDocsPreferredVersion} from './docsPreferredVersion';
export {
DocSidebarItemsExpandedStateProvider,
useDocSidebarItemsExpandedState,
} from './docSidebarItemsExpandedState';
export {DocsVersionProvider, useDocsVersion} from './docsVersion';
export {DocsSidebarProvider, useDocsSidebar} from './docsSidebar';
export {DocProvider, useDoc, type DocContextValue} from './doc';
export {
useDocsPreferredVersionByPluginId,
DocsPreferredVersionContextProvider,
} from './docsPreferredVersion';
export {
useDocsContextualSearchTags,
getDocsVersionSearchTag,
} from './docsSearch';
export type ActivePlugin = {
pluginId: string;
pluginData: GlobalPluginData;
};
export type ActiveDocContext = {
activeVersion?: GlobalVersion;
activeDoc?: GlobalDoc;
alternateDocVersions: {[versionName: string]: GlobalDoc};
};
export type GlobalDoc = {
/**
* For generated index pages, this is the `slug`, **not** `permalink`
* (without base URL). Because slugs have leading slashes but IDs don't,
* there won't be clashes.
*/
id: string;
path: string;
sidebar?: string;
unlisted?: boolean;
};
export type GlobalVersion = {
name: string;
label: string;
isLast: boolean;
path: string;
/** The doc with `slug: /`, or first doc in first sidebar */
mainDocId: string;
docs: GlobalDoc[];
/** Unversioned IDs. In development, this list is empty. */
draftIds: string[];
sidebars?: {[sidebarId: string]: GlobalSidebar};
};
export type GlobalSidebar = {
link?: {
label: string;
path: string;
};
// ... we may add other things here later
};
export type GlobalPluginData = {
path: string;
versions: GlobalVersion[];
breadcrumbs: boolean;
};
export type DocVersionSuggestions = {
/** Suggest the latest version */
latestVersionSuggestion: GlobalVersion;
/** Suggest the same doc, in latest version (if one exists) */
latestDocSuggestion?: GlobalDoc;
};
// Important to use a constant object to avoid React useEffect executions etc.
// see https://github.com/facebook/docusaurus/issues/5089
const StableEmptyObject = {};
// In blog-only mode, docs hooks are still used by the theme. We need a fail-
// safe fallback when the docs plugin is not in use
export const useAllDocsData = (): {[pluginId: string]: GlobalPluginData} =>
(useAllPluginInstancesData('docusaurus-plugin-content-docs') as
| {
[pluginId: string]: GlobalPluginData;
}
| undefined) ?? StableEmptyObject;
export const useDocsData = (pluginId: string | undefined): GlobalPluginData => {
try {
return usePluginData('docusaurus-plugin-content-docs', pluginId, {
failfast: true,
}) as GlobalPluginData;
} catch (error) {
throw new Error(
`You are using a feature of the Docusaurus docs plugin, but this plugin does not seem to be enabled${
pluginId === 'Default' ? '' : ` (pluginId=${pluginId}`
}`,
{cause: error as Error},
);
}
};
// TODO this feature should be provided by docusaurus core
export function useActivePlugin(
options: UseDataOptions = {},
): ActivePlugin | undefined {
const data = useAllDocsData();
const {pathname} = useLocation();
return getActivePlugin(data, pathname, options);
}
export function useActivePluginAndVersion(
options: UseDataOptions = {},
):
| {activePlugin: ActivePlugin; activeVersion: GlobalVersion | undefined}
| undefined {
const activePlugin = useActivePlugin(options);
const {pathname} = useLocation();
if (!activePlugin) {
return undefined;
}
const activeVersion = getActiveVersion(activePlugin.pluginData, pathname);
return {
activePlugin,
activeVersion,
};
}
/** Versions are returned ordered (most recent first). */
export function useVersions(pluginId: string | undefined): GlobalVersion[] {
const data = useDocsData(pluginId);
return data.versions;
}
export function useLatestVersion(pluginId: string | undefined): GlobalVersion {
const data = useDocsData(pluginId);
return getLatestVersion(data);
}
/**
* Returns `undefined` on doc-unrelated pages, because there's no version
* currently considered as active.
*/
export function useActiveVersion(
pluginId: string | undefined,
): GlobalVersion | undefined {
const data = useDocsData(pluginId);
const {pathname} = useLocation();
return getActiveVersion(data, pathname);
}
export function useActiveDocContext(
pluginId: string | undefined,
): ActiveDocContext {
const data = useDocsData(pluginId);
const {pathname} = useLocation();
return getActiveDocContext(data, pathname);
}
/**
* Useful to say "hey, you are not on the latest docs version, please switch"
*/
export function useDocVersionSuggestions(
pluginId: string | undefined,
): DocVersionSuggestions {
const data = useDocsData(pluginId);
const {pathname} = useLocation();
return getDocVersionSuggestions(data, pathname);
}