ant-design/components/anchor/AnchorLink.tsx

110 lines
2.9 KiB
TypeScript
Raw Normal View History

2016-10-28 14:02:55 +08:00
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
2016-11-03 16:45:13 +08:00
import AnchorHelper, { scrollTo } from './anchorHelper';
2016-10-28 14:02:55 +08:00
export interface AnchorLinkProps {
href: string;
onClick?: (href: string, component: Element) => void;
2016-11-03 16:45:13 +08:00
active?: boolean;
prefixCls?: string;
children?: any;
title: React.ReactNode;
offsetTop?: number;
bounds?: number;
2016-11-03 16:45:13 +08:00
target?: () => HTMLElement | Window;
2016-11-09 21:06:43 +08:00
affix?: boolean;
2016-10-28 14:02:55 +08:00
}
2016-11-03 16:45:13 +08:00
export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
static __ANT_ANCHOR_LINK = true;
2016-11-03 16:45:13 +08:00
static contextTypes = {
anchorHelper: PropTypes.any,
2016-11-03 16:45:13 +08:00
};
2016-10-28 16:53:59 +08:00
2016-11-03 16:45:13 +08:00
static defaultProps = {
href: '#',
prefixCls: 'ant-anchor',
};
context: {
anchorHelper: AnchorHelper;
};
private _component: HTMLAnchorElement;
2016-11-15 15:33:13 +08:00
setActiveAnchor() {
const { bounds, offsetTop, href, affix } = this.props;
const { anchorHelper } = this.context;
const active = affix && anchorHelper && anchorHelper.getCurrentAnchor(offsetTop, bounds) === href;
if (active && anchorHelper) {
anchorHelper.setActiveAnchor(this._component);
}
}
componentDidMount() {
this.setActiveAnchor();
}
componentDidUpdate() {
this.setActiveAnchor();
2016-11-03 16:45:13 +08:00
}
2016-11-09 14:22:38 +08:00
renderAnchorLink = (child: React.ReactChild) => {
// Here child is a ReactChild type
if (typeof child !== 'string' && typeof child !== 'number') {
const { href } = child.props;
if (href) {
this.context.anchorHelper.addLink(href);
return React.cloneElement(child, {
onClick: this.props.onClick,
prefixCls: this.props.prefixCls,
affix: this.props.affix,
offsetTop: this.props.offsetTop,
});
}
2016-11-03 16:45:13 +08:00
}
return child;
}
2016-11-09 14:22:38 +08:00
refsTo = (component: HTMLAnchorElement) => {
this._component = component;
}
scrollTo = (e: React.MouseEvent<HTMLAnchorElement>) => {
2016-11-18 17:25:30 +08:00
e.preventDefault();
2016-11-09 14:40:31 +08:00
const { onClick, href } = this.props;
const { anchorHelper } = this.context;
if (onClick) {
onClick(href, this._component);
2016-11-09 14:40:31 +08:00
} else {
const scrollToFn = anchorHelper ? anchorHelper.scrollTo : scrollTo;
scrollToFn(href, this.props.offsetTop);
2016-11-09 14:40:31 +08:00
}
}
2016-11-03 16:45:13 +08:00
render() {
const { prefixCls, href, children, title, bounds, offsetTop, affix } = this.props;
2016-11-03 16:45:13 +08:00
const { anchorHelper } = this.context;
const active = affix && anchorHelper && anchorHelper.getCurrentAnchor(offsetTop, bounds) === href;
const cls = classNames({
2016-11-03 16:45:13 +08:00
[`${prefixCls}-link`]: true,
[`${prefixCls}-link-active`]: active,
});
2016-11-09 14:22:38 +08:00
return (
<div className={cls}>
2016-11-09 14:40:31 +08:00
<a
ref={this.refsTo}
2016-11-09 14:22:38 +08:00
className={`${prefixCls}-link-title`}
2016-11-09 14:40:31 +08:00
onClick={this.scrollTo}
href={href}
title={typeof title === 'string' ? title : ''}
2016-11-09 14:22:38 +08:00
>
2016-11-09 14:40:31 +08:00
{title}
</a>
2016-11-09 14:22:38 +08:00
{React.Children.map(children, this.renderAnchorLink)}
</div>
);
2016-11-03 16:45:13 +08:00
}
}