You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
8.8 KiB

import classNames from 'classnames';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import * as React from 'react';
import Affix from '../affix';
import type { ConfigConsumerProps } from '../config-provider';
import { ConfigContext } from '../config-provider';
import getScroll from '../_util/getScroll';
import scrollTo from '../_util/scrollTo';
import AnchorContext from './context';
import useStyle from './style';
export type AnchorContainer = HTMLElement | Window;
function getDefaultContainer() {
return window;
}
function getOffsetTop(element: HTMLElement, container: AnchorContainer): number {
if (!element.getClientRects().length) {
return 0;
}
const rect = element.getBoundingClientRect();
if (rect.width || rect.height) {
if (container === window) {
container = element.ownerDocument!.documentElement!;
return rect.top - container.clientTop;
}
return rect.top - (container as HTMLElement).getBoundingClientRect().top;
}
return rect.top;
}
const sharpMatcherRegx = /#([\S ]+)$/;
interface Section {
link: string;
top: number;
}
export interface AnchorProps {
prefixCls?: string;
className?: string;
style?: React.CSSProperties;
children?: React.ReactNode;
offsetTop?: number;
bounds?: number;
affix?: boolean;
showInkInFixed?: boolean;
getContainer?: () => AnchorContainer;
/** Return customize highlight anchor */
getCurrentAnchor?: (activeLink: string) => string;
onClick?: (
e: React.MouseEvent<HTMLElement>,
link: { title: React.ReactNode; href: string },
) => void;
/** Scroll to target offset value, if none, it's offsetTop prop value or 0. */
targetOffset?: number;
/** Listening event when scrolling change active link */
onChange?: (currentActiveLink: string) => void;
}
interface InternalAnchorProps extends AnchorProps {
anchorPrefixCls: string;
rootClassName: string;
}
export interface AnchorState {
activeLink: null | string;
}
export interface AnchorDefaultProps extends AnchorProps {
prefixCls: string;
affix: boolean;
showInkInFixed: boolean;
getContainer: () => AnchorContainer;
}
export interface AntAnchor {
registerLink: (link: string) => void;
unregisterLink: (link: string) => void;
activeLink: string | null;
scrollTo: (link: string) => void;
onClick?: (
e: React.MouseEvent<HTMLElement>,
link: { title: React.ReactNode; href: string },
) => void;
}
const AnchorContent: React.FC<InternalAnchorProps> = props => {
const {
rootClassName,
anchorPrefixCls: prefixCls,
className = '',
style,
offsetTop,
affix = true,
showInkInFixed = false,
children,
bounds,
targetOffset,
onClick,
onChange,
getContainer,
getCurrentAnchor,
} = props;