1 | import _extends from 'babel-runtime/helpers/extends';
|
2 | import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
|
3 | import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
|
4 | import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
|
5 | import _inherits from 'babel-runtime/helpers/inherits';
|
6 | import classNames from 'classnames';
|
7 | import activeElement from 'dom-helpers/activeElement';
|
8 | import contains from 'dom-helpers/query/contains';
|
9 | import keycode from 'keycode';
|
10 | import React, { cloneElement } from 'react';
|
11 | import PropTypes from 'prop-types';
|
12 | import ReactDOM from 'react-dom';
|
13 | import all from 'prop-types-extra/lib/all';
|
14 | import elementType from 'prop-types-extra/lib/elementType';
|
15 | import isRequiredForA11y from 'prop-types-extra/lib/isRequiredForA11y';
|
16 | import uncontrollable from 'uncontrollable';
|
17 | import warning from 'warning';
|
18 |
|
19 | import ButtonGroup from './ButtonGroup';
|
20 | import DropdownMenu from './DropdownMenu';
|
21 | import DropdownToggle from './DropdownToggle';
|
22 | import { bsClass as setBsClass, prefix } from './utils/bootstrapUtils';
|
23 | import createChainedFunction from './utils/createChainedFunction';
|
24 | import { exclusiveRoles, requiredRoles } from './utils/PropTypes';
|
25 | import ValidComponentChildren from './utils/ValidComponentChildren';
|
26 |
|
27 | var TOGGLE_ROLE = DropdownToggle.defaultProps.bsRole;
|
28 | var MENU_ROLE = DropdownMenu.defaultProps.bsRole;
|
29 |
|
30 | var propTypes = {
|
31 | |
32 |
|
33 |
|
34 | dropup: PropTypes.bool,
|
35 |
|
36 | |
37 |
|
38 |
|
39 |
|
40 |
|
41 | id: isRequiredForA11y(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
|
42 |
|
43 | componentClass: elementType,
|
44 |
|
45 | |
46 |
|
47 |
|
48 |
|
49 | children: all(requiredRoles(TOGGLE_ROLE, MENU_ROLE), exclusiveRoles(MENU_ROLE)),
|
50 |
|
51 | |
52 |
|
53 |
|
54 | disabled: PropTypes.bool,
|
55 |
|
56 | |
57 |
|
58 |
|
59 | pullRight: PropTypes.bool,
|
60 |
|
61 | |
62 |
|
63 |
|
64 |
|
65 |
|
66 | open: PropTypes.bool,
|
67 |
|
68 | defaultOpen: PropTypes.bool,
|
69 |
|
70 | |
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 | onToggle: PropTypes.func,
|
80 |
|
81 | |
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 | onSelect: PropTypes.func,
|
89 |
|
90 | |
91 |
|
92 |
|
93 |
|
94 | role: PropTypes.string,
|
95 |
|
96 | |
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 | rootCloseEvent: PropTypes.oneOf(['click', 'mousedown']),
|
104 |
|
105 | |
106 |
|
107 |
|
108 | onMouseEnter: PropTypes.func,
|
109 | |
110 |
|
111 |
|
112 | onMouseLeave: PropTypes.func
|
113 | };
|
114 |
|
115 | var defaultProps = {
|
116 | componentClass: ButtonGroup
|
117 | };
|
118 |
|
119 | var Dropdown = function (_React$Component) {
|
120 | _inherits(Dropdown, _React$Component);
|
121 |
|
122 | function Dropdown(props, context) {
|
123 | _classCallCheck(this, Dropdown);
|
124 |
|
125 | var _this = _possibleConstructorReturn(this, _React$Component.call(this, props, context));
|
126 |
|
127 | _this.handleClick = _this.handleClick.bind(_this);
|
128 | _this.handleKeyDown = _this.handleKeyDown.bind(_this);
|
129 | _this.handleClose = _this.handleClose.bind(_this);
|
130 |
|
131 | _this._focusInDropdown = false;
|
132 | _this.lastOpenEventType = null;
|
133 | return _this;
|
134 | }
|
135 |
|
136 | Dropdown.prototype.componentDidMount = function componentDidMount() {
|
137 | this.focusNextOnOpen();
|
138 | };
|
139 |
|
140 | Dropdown.prototype.componentWillUpdate = function componentWillUpdate(nextProps) {
|
141 | if (!nextProps.open && this.props.open) {
|
142 | this._focusInDropdown = contains(ReactDOM.findDOMNode(this.menu), activeElement(document));
|
143 | }
|
144 | };
|
145 |
|
146 | Dropdown.prototype.componentDidUpdate = function componentDidUpdate(prevProps) {
|
147 | var open = this.props.open;
|
148 |
|
149 | var prevOpen = prevProps.open;
|
150 |
|
151 | if (open && !prevOpen) {
|
152 | this.focusNextOnOpen();
|
153 | }
|
154 |
|
155 | if (!open && prevOpen) {
|
156 |
|
157 |
|
158 | if (this._focusInDropdown) {
|
159 | this._focusInDropdown = false;
|
160 | this.focus();
|
161 | }
|
162 | }
|
163 | };
|
164 |
|
165 | Dropdown.prototype.focus = function focus() {
|
166 | var toggle = ReactDOM.findDOMNode(this.toggle);
|
167 |
|
168 | if (toggle && toggle.focus) {
|
169 | toggle.focus();
|
170 | }
|
171 | };
|
172 |
|
173 | Dropdown.prototype.focusNextOnOpen = function focusNextOnOpen() {
|
174 | var menu = this.menu;
|
175 |
|
176 | if (!menu.focusNext) {
|
177 | return;
|
178 | }
|
179 |
|
180 | if (this.lastOpenEventType === 'keydown' || this.props.role === 'menuitem') {
|
181 | menu.focusNext();
|
182 | }
|
183 | };
|
184 |
|
185 | Dropdown.prototype.handleClick = function handleClick(event) {
|
186 | if (this.props.disabled) {
|
187 | return;
|
188 | }
|
189 |
|
190 | this.toggleOpen(event, { source: 'click' });
|
191 | };
|
192 |
|
193 | Dropdown.prototype.handleClose = function handleClose(event, eventDetails) {
|
194 | if (!this.props.open) {
|
195 | return;
|
196 | }
|
197 |
|
198 | this.toggleOpen(event, eventDetails);
|
199 | };
|
200 |
|
201 | Dropdown.prototype.handleKeyDown = function handleKeyDown(event) {
|
202 | if (this.props.disabled) {
|
203 | return;
|
204 | }
|
205 |
|
206 | switch (event.keyCode) {
|
207 | case keycode.codes.down:
|
208 | if (!this.props.open) {
|
209 | this.toggleOpen(event, { source: 'keydown' });
|
210 | } else if (this.menu.focusNext) {
|
211 | this.menu.focusNext();
|
212 | }
|
213 | event.preventDefault();
|
214 | break;
|
215 | case keycode.codes.esc:
|
216 | case keycode.codes.tab:
|
217 | this.handleClose(event, { source: 'keydown' });
|
218 | break;
|
219 | default:
|
220 | }
|
221 | };
|
222 |
|
223 | Dropdown.prototype.toggleOpen = function toggleOpen(event, eventDetails) {
|
224 | var open = !this.props.open;
|
225 |
|
226 | if (open) {
|
227 | this.lastOpenEventType = eventDetails.source;
|
228 | }
|
229 |
|
230 | if (this.props.onToggle) {
|
231 | this.props.onToggle(open, event, eventDetails);
|
232 | }
|
233 | };
|
234 |
|
235 | Dropdown.prototype.renderMenu = function renderMenu(child, _ref) {
|
236 | var _this2 = this;
|
237 |
|
238 | var id = _ref.id,
|
239 | onSelect = _ref.onSelect,
|
240 | rootCloseEvent = _ref.rootCloseEvent,
|
241 | props = _objectWithoutProperties(_ref, ['id', 'onSelect', 'rootCloseEvent']);
|
242 |
|
243 | var ref = function ref(c) {
|
244 | _this2.menu = c;
|
245 | };
|
246 |
|
247 | if (typeof child.ref === 'string') {
|
248 | process.env.NODE_ENV !== 'production' ? warning(false, 'String refs are not supported on `<Dropdown.Menu>` components. ' + 'To apply a ref to the component use the callback signature:\n\n ' + 'https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute') : void 0;
|
249 | } else {
|
250 | ref = createChainedFunction(child.ref, ref);
|
251 | }
|
252 |
|
253 | return cloneElement(child, _extends({}, props, {
|
254 | ref: ref,
|
255 | labelledBy: id,
|
256 | bsClass: prefix(props, 'menu'),
|
257 | onClose: createChainedFunction(child.props.onClose, this.handleClose),
|
258 | onSelect: createChainedFunction(child.props.onSelect, onSelect, function (key, event) {
|
259 | return _this2.handleClose(event, { source: 'select' });
|
260 | }),
|
261 | rootCloseEvent: rootCloseEvent
|
262 | }));
|
263 | };
|
264 |
|
265 | Dropdown.prototype.renderToggle = function renderToggle(child, props) {
|
266 | var _this3 = this;
|
267 |
|
268 | var ref = function ref(c) {
|
269 | _this3.toggle = c;
|
270 | };
|
271 |
|
272 | if (typeof child.ref === 'string') {
|
273 | process.env.NODE_ENV !== 'production' ? warning(false, 'String refs are not supported on `<Dropdown.Toggle>` components. ' + 'To apply a ref to the component use the callback signature:\n\n ' + 'https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute') : void 0;
|
274 | } else {
|
275 | ref = createChainedFunction(child.ref, ref);
|
276 | }
|
277 |
|
278 | return cloneElement(child, _extends({}, props, {
|
279 | ref: ref,
|
280 | bsClass: prefix(props, 'toggle'),
|
281 | onClick: createChainedFunction(child.props.onClick, this.handleClick),
|
282 | onKeyDown: createChainedFunction(child.props.onKeyDown, this.handleKeyDown)
|
283 | }));
|
284 | };
|
285 |
|
286 | Dropdown.prototype.render = function render() {
|
287 | var _classes,
|
288 | _this4 = this;
|
289 |
|
290 | var _props = this.props,
|
291 | Component = _props.componentClass,
|
292 | id = _props.id,
|
293 | dropup = _props.dropup,
|
294 | disabled = _props.disabled,
|
295 | pullRight = _props.pullRight,
|
296 | open = _props.open,
|
297 | onSelect = _props.onSelect,
|
298 | role = _props.role,
|
299 | bsClass = _props.bsClass,
|
300 | className = _props.className,
|
301 | rootCloseEvent = _props.rootCloseEvent,
|
302 | children = _props.children,
|
303 | props = _objectWithoutProperties(_props, ['componentClass', 'id', 'dropup', 'disabled', 'pullRight', 'open', 'onSelect', 'role', 'bsClass', 'className', 'rootCloseEvent', 'children']);
|
304 |
|
305 | delete props.onToggle;
|
306 |
|
307 | var classes = (_classes = {}, _classes[bsClass] = true, _classes.open = open, _classes.disabled = disabled, _classes);
|
308 |
|
309 | if (dropup) {
|
310 | classes[bsClass] = false;
|
311 | classes.dropup = true;
|
312 | }
|
313 |
|
314 |
|
315 |
|
316 |
|
317 | return React.createElement(
|
318 | Component,
|
319 | _extends({}, props, { className: classNames(className, classes) }),
|
320 | ValidComponentChildren.map(children, function (child) {
|
321 | switch (child.props.bsRole) {
|
322 | case TOGGLE_ROLE:
|
323 | return _this4.renderToggle(child, {
|
324 | id: id,
|
325 | disabled: disabled,
|
326 | open: open,
|
327 | role: role,
|
328 | bsClass: bsClass
|
329 | });
|
330 | case MENU_ROLE:
|
331 | return _this4.renderMenu(child, {
|
332 | id: id,
|
333 | open: open,
|
334 | pullRight: pullRight,
|
335 | bsClass: bsClass,
|
336 | onSelect: onSelect,
|
337 | rootCloseEvent: rootCloseEvent
|
338 | });
|
339 | default:
|
340 | return child;
|
341 | }
|
342 | })
|
343 | );
|
344 | };
|
345 |
|
346 | return Dropdown;
|
347 | }(React.Component);
|
348 |
|
349 | Dropdown.propTypes = propTypes;
|
350 | Dropdown.defaultProps = defaultProps;
|
351 |
|
352 | setBsClass('dropdown', Dropdown);
|
353 |
|
354 | var UncontrolledDropdown = uncontrollable(Dropdown, { open: 'onToggle' });
|
355 |
|
356 | UncontrolledDropdown.Toggle = DropdownToggle;
|
357 | UncontrolledDropdown.Menu = DropdownMenu;
|
358 |
|
359 | export default UncontrolledDropdown; |
\ | No newline at end of file |