-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathindex.js
128 lines (106 loc) · 2.62 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/**
* External dependencies
*/
import { createElement, Component } from 'preact';
import { connect } from 'preact-redux';
import classNames from 'classcat';
import { startsWith, omit, assign, uniq, compact } from 'lodash';
/**
* Internal dependencies
*/
import { SITE_URL } from 'constant';
import { preloadRoute, pushRoute } from 'state/routing/actions';
class Link extends Component {
static defaultProps = {
onClick: () => {},
onMouseEnter: () => {},
onMouseLeave: () => {},
to: '',
};
constructor() {
super( ...arguments );
this.state = {
isMouseOver: false,
};
}
componentWillReceiveProps( nextProps ) {
const { to, preload, onPreload } = nextProps;
const { isMouseOver } = this.state;
if ( this.props.to !== to && preload && onPreload && isMouseOver ) {
onPreload( to );
}
}
isManagedPath() {
return '/' === this.props.to[ 0 ];
}
isLocalPath() {
const { to } = this.props;
return this.isManagedPath() || startsWith( to, location.origin + '/' );
}
onClick = ( event ) => {
const { onNavigate, to, onClick } = this.props;
if ( ! this.isManagedPath() ) {
return;
}
event.preventDefault();
onNavigate( to );
onClick();
};
onMouseEnter = ( event ) => {
const { onMouseEnter, preload, onPreload, to } = this.props;
// Preserve original handler of rendering parent
onMouseEnter( event );
// If preload intent, trigger on mouse over
if ( preload ) {
onPreload( to );
}
// Set mouseover as state so we can track prop changes and re-trigger
// preload if the link changes while mouse within
this.setState( { isMouseOver: true } );
};
onMouseLeave = ( event ) => {
const { onMouseLeave } = this.props;
const { isMouseOver } = this.state;
// Preserve original handler of rendering parent
onMouseLeave( event );
if ( isMouseOver ) {
this.setState( { isMouseOver: false } );
}
};
render() {
const { to, className } = this.props;
const props = omit( this.props, 'to', 'pushRoute', 'preload' );
const classes = classNames( [ 'link', className ] );
if ( ! this.isLocalPath() ) {
assign( props, {
target: '_blank',
rel: uniq( compact( [
props.rel,
'noopener',
'noreferrer',
] ) ).join( ' ' ),
} );
}
// Prefix with site URL if root-relative path
let href = to;
if ( this.isManagedPath() ) {
href = SITE_URL + href;
}
return (
<a
{ ...props }
className={ classes }
href={ href }
onClick={ this.onClick }
onMouseEnter={ this.onMouseEnter }
onMouseLeave={ this.onMouseLeave } />
);
}
}
export default connect(
null,
{
onNavigate: pushRoute,
onPreload: preloadRoute,
}
)( Link );