aboutsummaryrefslogtreecommitdiffstats
path: root/packages/react-shared
diff options
context:
space:
mode:
Diffstat (limited to 'packages/react-shared')
-rw-r--r--packages/react-shared/src/components/link.tsx154
1 files changed, 82 insertions, 72 deletions
diff --git a/packages/react-shared/src/components/link.tsx b/packages/react-shared/src/components/link.tsx
index 6200bfbd3..7b22dc4fa 100644
--- a/packages/react-shared/src/components/link.tsx
+++ b/packages/react-shared/src/components/link.tsx
@@ -18,84 +18,94 @@ export interface LinkProps {
containerId?: string;
}
+export interface LinkState {}
+
/**
* A generic link component which let's the developer render internal, external and scroll-to-hash links, and
* their associated behaviors with a single link component. Many times we want a menu including a combination of
* internal, external and scroll links and the abstraction of the differences of rendering each types of link
* makes it much easier to do so.
*/
-export const Link: React.StatelessComponent<LinkProps> = ({
- style,
- className,
- type,
- to,
- shouldOpenInNewTab,
- children,
- onMouseOver,
- onMouseLeave,
- onMouseEnter,
- containerId,
-}) => {
- const styleWithDefault = {
- textDecoration: 'none',
- ...style,
+export class Link extends React.Component<LinkProps, LinkState> {
+ public static defaultProps: Partial<LinkProps> = {
+ type: LinkType.ReactRoute,
+ shouldOpenInNewTab: false,
+ style: {},
+ className: '',
+ onMouseOver: _.noop.bind(_),
+ onMouseLeave: _.noop.bind(_),
+ onMouseEnter: _.noop.bind(_),
+ containerId: constants.DOCS_CONTAINER_ID,
};
-
- switch (type) {
- case LinkType.External:
- return (
- <a
- target={shouldOpenInNewTab ? '_blank' : ''}
- className={className}
- style={styleWithDefault}
- href={to}
- onMouseOver={onMouseOver}
- onMouseEnter={onMouseEnter}
- onMouseLeave={onMouseLeave}
- >
- {children}
- </a>
- );
- case LinkType.ReactRoute:
- return (
- <ReactRounterLink
- to={to}
- className={className}
- style={styleWithDefault}
- target={shouldOpenInNewTab ? '_blank' : ''}
- onMouseOver={onMouseOver}
- onMouseEnter={onMouseEnter}
- onMouseLeave={onMouseLeave}
- >
- {children}
- </ReactRounterLink>
- );
- case LinkType.ReactScroll:
- return (
- <ScrollLink
- to={to}
- offset={0}
- hashSpy={true}
- duration={constants.DOCS_SCROLL_DURATION_MS}
- containerId={containerId}
- >
- {children}
- </ScrollLink>
- );
- default:
- throw new Error(`Unrecognized LinkType: ${type}`);
+ private _outerReactScrollSpan: HTMLSpanElement | null;
+ constructor(props: LinkProps) {
+ super(props);
+ this._outerReactScrollSpan = null;
}
-};
-
-Link.defaultProps = {
- type: LinkType.ReactRoute,
- shouldOpenInNewTab: false,
- style: {},
- className: '',
- onMouseOver: _.noop.bind(_),
- onMouseLeave: _.noop.bind(_),
- onMouseEnter: _.noop.bind(_),
- containerId: constants.DOCS_CONTAINER_ID,
-};
+ public render(): React.ReactNode {
+ const styleWithDefault = {
+ textDecoration: 'none',
+ cursor: 'pointer',
+ ...this.props.style,
+ };
-Link.displayName = 'Link';
+ switch (this.props.type) {
+ case LinkType.External:
+ return (
+ <a
+ target={this.props.shouldOpenInNewTab ? '_blank' : ''}
+ className={this.props.className}
+ style={styleWithDefault}
+ href={this.props.to}
+ onMouseOver={this.props.onMouseOver}
+ onMouseEnter={this.props.onMouseEnter}
+ onMouseLeave={this.props.onMouseLeave}
+ >
+ {this.props.children}
+ </a>
+ );
+ case LinkType.ReactRoute:
+ return (
+ <ReactRounterLink
+ to={this.props.to}
+ className={this.props.className}
+ style={styleWithDefault}
+ target={this.props.shouldOpenInNewTab ? '_blank' : ''}
+ onMouseOver={this.props.onMouseOver}
+ onMouseEnter={this.props.onMouseEnter}
+ onMouseLeave={this.props.onMouseLeave}
+ >
+ {this.props.children}
+ </ReactRounterLink>
+ );
+ case LinkType.ReactScroll:
+ return (
+ <span ref={input => (this._outerReactScrollSpan = input)}>
+ <ScrollLink
+ to={this.props.to}
+ offset={0}
+ hashSpy={true}
+ duration={constants.DOCS_SCROLL_DURATION_MS}
+ containerId={this.props.containerId}
+ style={styleWithDefault}
+ >
+ <span onClick={this._onClickPropagateClickEventAroundScrollLink.bind(this)}>
+ {this.props.children}
+ </span>
+ </ScrollLink>
+ </span>
+ );
+ default:
+ throw new Error(`Unrecognized LinkType: ${this.props.type}`);
+ }
+ }
+ // HACK(fabio): For some reason, the react-scroll link decided to stop the propagation of click events.
+ // We do however rely on these events being propagated in certain scenarios (e.g when the link
+ // is within a dropdown we want to close upon being clicked). Because of this, we registry the
+ // click event of an inner span, and pass it around the react-scroll link to an outer span.
+ private _onClickPropagateClickEventAroundScrollLink(): void {
+ if (!_.isNull(this._outerReactScrollSpan)) {
+ this._outerReactScrollSpan.click();
+ }
+ }
+}