UNPKG

3.35 kBJavaScriptView Raw
1import _extends from 'babel-runtime/helpers/extends';
2import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
3import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
4import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
5import _inherits from 'babel-runtime/helpers/inherits';
6import React from 'react';
7import PropTypes from 'prop-types';
8import elementType from 'prop-types-extra/lib/elementType';
9
10import createChainedFunction from './utils/createChainedFunction';
11
12var propTypes = {
13 href: PropTypes.string,
14 onClick: PropTypes.func,
15 onKeyDown: PropTypes.func,
16 disabled: PropTypes.bool,
17 role: PropTypes.string,
18 tabIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
19 /**
20 * this is sort of silly but needed for Button
21 */
22 componentClass: elementType
23};
24
25var defaultProps = {
26 componentClass: 'a'
27};
28
29function isTrivialHref(href) {
30 return !href || href.trim() === '#';
31}
32
33/**
34 * There are situations due to browser quirks or Bootstrap CSS where
35 * an anchor tag is needed, when semantically a button tag is the
36 * better choice. SafeAnchor ensures that when an anchor is used like a
37 * button its accessible. It also emulates input `disabled` behavior for
38 * links, which is usually desirable for Buttons, NavItems, MenuItems, etc.
39 */
40
41var SafeAnchor = function (_React$Component) {
42 _inherits(SafeAnchor, _React$Component);
43
44 function SafeAnchor(props, context) {
45 _classCallCheck(this, SafeAnchor);
46
47 var _this = _possibleConstructorReturn(this, _React$Component.call(this, props, context));
48
49 _this.handleClick = _this.handleClick.bind(_this);
50 _this.handleKeyDown = _this.handleKeyDown.bind(_this);
51 return _this;
52 }
53
54 SafeAnchor.prototype.handleClick = function handleClick(event) {
55 var _props = this.props,
56 disabled = _props.disabled,
57 href = _props.href,
58 onClick = _props.onClick;
59
60
61 if (disabled || isTrivialHref(href)) {
62 event.preventDefault();
63 }
64
65 if (disabled) {
66 event.stopPropagation();
67 return;
68 }
69
70 if (onClick) {
71 onClick(event);
72 }
73 };
74
75 SafeAnchor.prototype.handleKeyDown = function handleKeyDown(event) {
76 if (event.key === ' ') {
77 event.preventDefault();
78 this.handleClick(event);
79 }
80 };
81
82 SafeAnchor.prototype.render = function render() {
83 var _props2 = this.props,
84 Component = _props2.componentClass,
85 disabled = _props2.disabled,
86 onKeyDown = _props2.onKeyDown,
87 props = _objectWithoutProperties(_props2, ['componentClass', 'disabled', 'onKeyDown']);
88
89 if (isTrivialHref(props.href)) {
90 props.role = props.role || 'button';
91 // we want to make sure there is a href attribute on the node
92 // otherwise, the cursor incorrectly styled (except with role='button')
93 props.href = props.href || '#';
94 }
95
96 if (disabled) {
97 props.tabIndex = -1;
98 props.style = _extends({ pointerEvents: 'none' }, props.style);
99 }
100
101 return React.createElement(Component, _extends({}, props, {
102 onClick: this.handleClick,
103 onKeyDown: createChainedFunction(this.handleKeyDown, onKeyDown)
104 }));
105 };
106
107 return SafeAnchor;
108}(React.Component);
109
110SafeAnchor.propTypes = propTypes;
111SafeAnchor.defaultProps = defaultProps;
112
113export default SafeAnchor;
\No newline at end of file