1 | import React from 'react';
|
2 | import PropTypes from 'prop-types';
|
3 | import classNames from 'classnames';
|
4 | import { Reference } from 'react-popper';
|
5 | import { DropdownContext } from './DropdownContext';
|
6 | import { mapToCssModules, tagPropType } from './utils';
|
7 | import Button from './Button';
|
8 |
|
9 | const propTypes = {
|
10 | caret: PropTypes.bool,
|
11 | color: PropTypes.string,
|
12 | children: PropTypes.node,
|
13 | className: PropTypes.string,
|
14 | cssModule: PropTypes.object,
|
15 | disabled: PropTypes.bool,
|
16 | onClick: PropTypes.func,
|
17 | 'aria-haspopup': PropTypes.bool,
|
18 | split: PropTypes.bool,
|
19 | tag: tagPropType,
|
20 | nav: PropTypes.bool,
|
21 | innerRef: PropTypes.oneOfType([
|
22 | PropTypes.object,
|
23 | PropTypes.string,
|
24 | PropTypes.func,
|
25 | ]),
|
26 | };
|
27 |
|
28 | const defaultProps = {
|
29 | color: 'secondary',
|
30 | 'aria-haspopup': true,
|
31 | };
|
32 |
|
33 | class DropdownToggle extends React.Component {
|
34 | constructor(props) {
|
35 | super(props);
|
36 |
|
37 | this.onClick = this.onClick.bind(this);
|
38 | }
|
39 |
|
40 | onClick(e) {
|
41 | if (this.props.disabled || this.context.disabled) {
|
42 | e.preventDefault();
|
43 | return;
|
44 | }
|
45 |
|
46 | if (this.props.nav && !this.props.tag) {
|
47 | e.preventDefault();
|
48 | }
|
49 |
|
50 | if (this.props.onClick) {
|
51 | this.props.onClick(e);
|
52 | }
|
53 |
|
54 | this.context.toggle(e);
|
55 | }
|
56 |
|
57 | getRole() {
|
58 | return this.context.menuRole || this.props['aria-haspopup'];
|
59 | }
|
60 |
|
61 | render() {
|
62 | const {
|
63 | className,
|
64 | color,
|
65 | cssModule,
|
66 | caret,
|
67 | split,
|
68 | nav,
|
69 | tag,
|
70 | innerRef,
|
71 | ...props
|
72 | } = this.props;
|
73 | const ariaLabel = props['aria-label'] || 'Toggle Dropdown';
|
74 | const classes = mapToCssModules(
|
75 | classNames(className, {
|
76 | 'dropdown-toggle': caret || split,
|
77 | 'dropdown-toggle-split': split,
|
78 | 'nav-link': nav,
|
79 | }),
|
80 | cssModule,
|
81 | );
|
82 | const children =
|
83 | typeof props.children !== 'undefined' ? (
|
84 | props.children
|
85 | ) : (
|
86 | <span className="visually-hidden">{ariaLabel}</span>
|
87 | );
|
88 |
|
89 | let Tag;
|
90 |
|
91 | if (nav && !tag) {
|
92 | Tag = 'a';
|
93 | props.href = '#';
|
94 | } else if (!tag) {
|
95 | Tag = Button;
|
96 | props.color = color;
|
97 | props.cssModule = cssModule;
|
98 | } else {
|
99 | Tag = tag;
|
100 | }
|
101 |
|
102 |
|
103 | const returnFunction = ({ ref }) => {
|
104 | const handleRef = (tagRef) => {
|
105 | ref(tagRef);
|
106 | const { onToggleRef } = this.context;
|
107 | if (onToggleRef) onToggleRef(tagRef);
|
108 | };
|
109 |
|
110 | return (
|
111 | <Tag
|
112 | {...props}
|
113 | {...{ [typeof Tag === 'string' ? 'ref' : 'innerRef']: handleRef }}
|
114 | className={classes}
|
115 | onClick={this.onClick}
|
116 | aria-expanded={this.context.isOpen}
|
117 | aria-haspopup={this.getRole()}
|
118 | children={children}
|
119 | />
|
120 | );
|
121 | };
|
122 |
|
123 |
|
124 | if (this.context.inNavbar) {
|
125 | return <>{returnFunction({ ref: this.context.onToggleRef })}</>;
|
126 | }
|
127 |
|
128 | // Normal rendering if component not in NavBar
|
129 | return <Reference innerRef={innerRef}>{returnFunction}</Reference>;
|
130 | }
|
131 | }
|
132 |
|
133 | DropdownToggle.propTypes = propTypes;
|
134 | DropdownToggle.defaultProps = defaultProps;
|
135 | DropdownToggle.contextType = DropdownContext;
|
136 |
|
137 | export default DropdownToggle;
|
138 |
|
\ | No newline at end of file |