mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-20 11:37:52 +02:00
feat(theme-common): JSDoc for all APIs (#6974)
* feat(theme-common): JSDoc for all APIs * fix tests
This commit is contained in:
parent
4103fef11e
commit
b456a64f61
48 changed files with 871 additions and 679 deletions
|
@ -9,8 +9,14 @@ import {useState, useCallback, useRef} from 'react';
|
|||
import {useLocationChange} from '../utils/useLocationChange';
|
||||
import {useScrollPosition} from '../utils/scrollUtils';
|
||||
|
||||
/**
|
||||
* Wires the imperative logic of a hideable navbar.
|
||||
* @param hideOnScroll If `false`, this hook is basically a no-op.
|
||||
*/
|
||||
export function useHideableNavbar(hideOnScroll: boolean): {
|
||||
/** A ref to the navbar component. Plug this into the actual element. */
|
||||
readonly navbarRef: (node: HTMLElement | null) => void;
|
||||
/** If `false`, the navbar component should not be rendered. */
|
||||
readonly isNavbarVisible: boolean;
|
||||
} {
|
||||
const [isNavbarVisible, setIsNavbarVisible] = useState(hideOnScroll);
|
||||
|
@ -29,7 +35,8 @@ export function useHideableNavbar(hideOnScroll: boolean): {
|
|||
|
||||
const scrollTop = currentPosition.scrollY;
|
||||
|
||||
// It needed for mostly to handle rubber band scrolling
|
||||
// Needed mostly for handling rubber band scrolling.
|
||||
// See https://github.com/facebook/docusaurus/pull/5721
|
||||
if (scrollTop < navbarHeight.current) {
|
||||
setIsNavbarVisible(true);
|
||||
return;
|
||||
|
@ -66,8 +73,5 @@ export function useHideableNavbar(hideOnScroll: boolean): {
|
|||
setIsNavbarVisible(true);
|
||||
});
|
||||
|
||||
return {
|
||||
navbarRef,
|
||||
isNavbarVisible,
|
||||
};
|
||||
return {navbarRef, isNavbarVisible};
|
||||
}
|
||||
|
|
|
@ -12,7 +12,13 @@ import './styles.css';
|
|||
export const keyboardFocusedClassName = 'navigation-with-keyboard';
|
||||
|
||||
/**
|
||||
* Detect keyboard focus indicator to not show outline for mouse users
|
||||
* Side-effect that adds the `keyboardFocusedClassName` to the body element when
|
||||
* the keyboard has been pressed, or removes it when the mouse is clicked.
|
||||
*
|
||||
* The presence of this class name signals that the user may be using keyboard
|
||||
* for navigation, and the theme **must** add focus outline when this class name
|
||||
* is present. (And optionally not if it's absent, for design purposes)
|
||||
*
|
||||
* Inspired by https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2
|
||||
*/
|
||||
export function useKeyboardNavigation(): void {
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
|
||||
import {useEffect} from 'react';
|
||||
|
||||
/**
|
||||
* Side-effect that locks the document body's scroll throughout the lifetime of
|
||||
* the containing component. e.g. when the mobile sidebar is expanded.
|
||||
*/
|
||||
export function useLockBodyScroll(lock: boolean = true): void {
|
||||
useEffect(() => {
|
||||
document.body.style.overflow = lock ? 'hidden' : 'visible';
|
||||
|
||||
return () => {
|
||||
document.body.style.overflow = 'visible';
|
||||
};
|
||||
|
|
|
@ -9,6 +9,10 @@ import defaultTheme from 'prism-react-renderer/themes/palenight';
|
|||
import {useColorMode} from '../contexts/colorMode';
|
||||
import {useThemeConfig} from '../utils/useThemeConfig';
|
||||
|
||||
/**
|
||||
* Returns a color-mode-dependent Prism theme: whatever the user specified in
|
||||
* the config. Falls back to `palenight`.
|
||||
*/
|
||||
export function usePrismTheme(): typeof defaultTheme {
|
||||
const {prism} = useThemeConfig();
|
||||
const {colorMode} = useColorMode();
|
||||
|
|
|
@ -11,9 +11,22 @@ import {useCallback, useEffect, useState} from 'react';
|
|||
|
||||
const SEARCH_PARAM_QUERY = 'q';
|
||||
|
||||
/** Some utility functions around search queries. */
|
||||
export function useSearchPage(): {
|
||||
/**
|
||||
* Works hand-in-hand with `setSearchQuery`; whatever the user has inputted
|
||||
* into the search box.
|
||||
*/
|
||||
searchQuery: string;
|
||||
/**
|
||||
* Set a new search query. In addition to updating `searchQuery`, this handle
|
||||
* also mutates the location and appends the query.
|
||||
*/
|
||||
setSearchQuery: (newSearchQuery: string) => void;
|
||||
/**
|
||||
* Given a query, this handle generates the corresponding search page link,
|
||||
* with base URL prepended.
|
||||
*/
|
||||
generateSearchPageLink: (targetSearchQuery: string) => string;
|
||||
} {
|
||||
const history = useHistory();
|
||||
|
@ -52,7 +65,9 @@ export function useSearchPage(): {
|
|||
const generateSearchPageLink = useCallback(
|
||||
(targetSearchQuery: string) =>
|
||||
// Refer to https://github.com/facebook/docusaurus/pull/2838
|
||||
`${baseUrl}search?q=${encodeURIComponent(targetSearchQuery)}`,
|
||||
`${baseUrl}search?${SEARCH_PARAM_QUERY}=${encodeURIComponent(
|
||||
targetSearchQuery,
|
||||
)}`,
|
||||
[baseUrl],
|
||||
);
|
||||
|
||||
|
|
|
@ -11,8 +11,10 @@ import {useThemeConfig} from '../utils/useThemeConfig';
|
|||
// TODO make the hardcoded theme-classic classnames configurable (or add them
|
||||
// to ThemeClassNames?)
|
||||
|
||||
// If the anchor has no height and is just a "marker" in the dom; we'll use the
|
||||
// parent (normally the link text) rect boundaries instead
|
||||
/**
|
||||
* If the anchor has no height and is just a "marker" in the DOM; we'll use the
|
||||
* parent (normally the link text) rect boundaries instead
|
||||
*/
|
||||
function getVisibleBoundingClientRect(element: HTMLElement): DOMRect {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const hasNoHeight = rect.top === rect.bottom;
|
||||
|
@ -24,7 +26,7 @@ function getVisibleBoundingClientRect(element: HTMLElement): DOMRect {
|
|||
|
||||
/**
|
||||
* Considering we divide viewport into 2 zones of each 50vh, this returns true
|
||||
* if an element is in the first zone (ie, appear in viewport, near the top)
|
||||
* if an element is in the first zone (i.e., appear in viewport, near the top)
|
||||
*/
|
||||
function isInViewportTopHalf(boundingRect: DOMRect) {
|
||||
return boundingRect.top > 0 && boundingRect.bottom < window.innerHeight / 2;
|
||||
|
@ -114,12 +116,23 @@ function useAnchorTopOffsetRef() {
|
|||
}
|
||||
|
||||
export type TOCHighlightConfig = {
|
||||
/** A class name that all TOC links share. */
|
||||
linkClassName: string;
|
||||
/** The class name applied to the active (highlighted) link. */
|
||||
linkActiveClassName: string;
|
||||
/**
|
||||
* The minimum heading level that the TOC includes. Only headings that are in
|
||||
* this range will be eligible as "active heading".
|
||||
*/
|
||||
minHeadingLevel: number;
|
||||
/** @see {@link TOCHighlightConfig.minHeadingLevel} */
|
||||
maxHeadingLevel: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Side-effect that applies the active class name to the TOC heading that the
|
||||
* user is currently viewing. Disabled when `config` is undefined.
|
||||
*/
|
||||
export function useTOCHighlight(config: TOCHighlightConfig | undefined): void {
|
||||
const lastActiveLinkRef = useRef<HTMLAnchorElement | undefined>(undefined);
|
||||
|
||||
|
|
|
@ -12,12 +12,6 @@ import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
|||
const windowSizes = {
|
||||
desktop: 'desktop',
|
||||
mobile: 'mobile',
|
||||
|
||||
// This "ssr" value is very important to handle hydration FOUC / layout shifts
|
||||
// You have to handle server-rendering explicitly on the call-site
|
||||
// On the server, you may need to render BOTH the mobile/desktop elements (and
|
||||
// hide one of them with mediaquery)
|
||||
// We don't return "undefined" on purpose, to make it more explicit
|
||||
ssr: 'ssr',
|
||||
} as const;
|
||||
|
||||
|
@ -34,13 +28,21 @@ function getWindowSize() {
|
|||
: windowSizes.mobile;
|
||||
}
|
||||
|
||||
// Simulate the SSR window size in dev, so that potential hydration FOUC/layout
|
||||
// shift problems can be seen in dev too!
|
||||
const DevSimulateSSR = process.env.NODE_ENV === 'development' && true;
|
||||
|
||||
// This hook returns an enum value on purpose!
|
||||
// We don't want it to return the actual width value, for resize perf reasons
|
||||
// We only want to re-render once a breakpoint is crossed
|
||||
/**
|
||||
* Gets the current window size as an enum value. We don't want it to return the
|
||||
* actual width value, so that it only re-renders once a breakpoint is crossed.
|
||||
*
|
||||
* It may return `"ssr"`, which is very important to handle hydration FOUC or
|
||||
* layout shifts. You have to handle it explicitly upfront. On the server, you
|
||||
* may need to render BOTH the mobile/desktop elements (and hide one of them
|
||||
* with mediaquery). We don't return `undefined` on purpose, to make it more
|
||||
* explicit.
|
||||
*
|
||||
* In development mode, this hook will still return `"ssr"` for one second, to
|
||||
* catch potential layout shifts, similar to strict mode calling effects twice.
|
||||
*/
|
||||
export function useWindowSize(): WindowSize {
|
||||
const [windowSize, setWindowSize] = useState<WindowSize>(() => {
|
||||
if (DevSimulateSSR) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue