UNPKG

12.6 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireWildcard = require("@babel/runtime-corejs2/helpers/interopRequireWildcard");
4
5var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
6
7exports.__esModule = true;
8exports.default = void 0;
9
10var _extends2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/extends"));
11
12var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/objectWithoutPropertiesLoose"));
13
14var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inheritsLoose"));
15
16var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/assertThisInitialized"));
17
18var _classnames = _interopRequireDefault(require("classnames"));
19
20var _activeElement = _interopRequireDefault(require("dom-helpers/activeElement"));
21
22var _contains = _interopRequireDefault(require("dom-helpers/query/contains"));
23
24var _keycode = _interopRequireDefault(require("keycode"));
25
26var _react = _interopRequireWildcard(require("react"));
27
28var _propTypes = _interopRequireDefault(require("prop-types"));
29
30var _reactDom = _interopRequireDefault(require("react-dom"));
31
32var _all = _interopRequireDefault(require("prop-types-extra/lib/all"));
33
34var _elementType = _interopRequireDefault(require("prop-types-extra/lib/elementType"));
35
36var _isRequiredForA11y = _interopRequireDefault(require("prop-types-extra/lib/isRequiredForA11y"));
37
38var _uncontrollable = _interopRequireDefault(require("uncontrollable"));
39
40var _warning = _interopRequireDefault(require("warning"));
41
42var _ButtonGroup = _interopRequireDefault(require("./ButtonGroup"));
43
44var _DropdownMenu = _interopRequireDefault(require("./DropdownMenu"));
45
46var _DropdownToggle = _interopRequireDefault(require("./DropdownToggle"));
47
48var _bootstrapUtils = require("./utils/bootstrapUtils");
49
50var _createChainedFunction = _interopRequireDefault(require("./utils/createChainedFunction"));
51
52var _PropTypes = require("./utils/PropTypes");
53
54var _ValidComponentChildren = _interopRequireDefault(require("./utils/ValidComponentChildren"));
55
56var TOGGLE_ROLE = _DropdownToggle.default.defaultProps.bsRole;
57var MENU_ROLE = _DropdownMenu.default.defaultProps.bsRole;
58var propTypes = {
59 /**
60 * The menu will open above the dropdown button, instead of below it.
61 */
62 dropup: _propTypes.default.bool,
63
64 /**
65 * An html id attribute, necessary for assistive technologies, such as screen readers.
66 * @type {string|number}
67 * @required
68 */
69 id: (0, _isRequiredForA11y.default)(_propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number])),
70 componentClass: _elementType.default,
71
72 /**
73 * The children of a Dropdown may be a `<Dropdown.Toggle>` or a `<Dropdown.Menu>`.
74 * @type {node}
75 */
76 children: (0, _all.default)((0, _PropTypes.requiredRoles)(TOGGLE_ROLE, MENU_ROLE), (0, _PropTypes.exclusiveRoles)(MENU_ROLE)),
77
78 /**
79 * Whether or not component is disabled.
80 */
81 disabled: _propTypes.default.bool,
82
83 /**
84 * Align the menu to the right side of the Dropdown toggle
85 */
86 pullRight: _propTypes.default.bool,
87
88 /**
89 * Whether or not the Dropdown is visible.
90 *
91 * @controllable onToggle
92 */
93 open: _propTypes.default.bool,
94 defaultOpen: _propTypes.default.bool,
95
96 /**
97 * A callback fired when the Dropdown wishes to change visibility. Called with the requested
98 * `open` value, the DOM event, and the source that fired it: `'click'`,`'keydown'`,`'rootClose'`, or `'select'`.
99 *
100 * ```js
101 * function(Boolean isOpen, Object event, { String source }) {}
102 * ```
103 * @controllable open
104 */
105 onToggle: _propTypes.default.func,
106
107 /**
108 * A callback fired when a menu item is selected.
109 *
110 * ```js
111 * (eventKey: any, event: Object) => any
112 * ```
113 */
114 onSelect: _propTypes.default.func,
115
116 /**
117 * If `'menuitem'`, causes the dropdown to behave like a menu item rather than
118 * a menu button.
119 */
120 role: _propTypes.default.string,
121
122 /**
123 * Which event when fired outside the component will cause it to be closed
124 *
125 * *Note: For custom dropdown components, you will have to pass the
126 * `rootCloseEvent` to `<RootCloseWrapper>` in your custom dropdown menu
127 * component ([similarly to how it is implemented in `<Dropdown.Menu>`](https://github.com/react-bootstrap/react-bootstrap/blob/v0.31.5/src/DropdownMenu.js#L115-L119)).*
128 */
129 rootCloseEvent: _propTypes.default.oneOf(['click', 'mousedown']),
130
131 /**
132 * @private
133 */
134 onMouseEnter: _propTypes.default.func,
135
136 /**
137 * @private
138 */
139 onMouseLeave: _propTypes.default.func
140};
141var defaultProps = {
142 componentClass: _ButtonGroup.default
143};
144
145var Dropdown =
146/*#__PURE__*/
147function (_React$Component) {
148 (0, _inheritsLoose2.default)(Dropdown, _React$Component);
149
150 function Dropdown(props, context) {
151 var _this;
152
153 _this = _React$Component.call(this, props, context) || this;
154 _this.handleClick = _this.handleClick.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
155 _this.handleKeyDown = _this.handleKeyDown.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
156 _this.handleClose = _this.handleClose.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
157 _this._focusInDropdown = false;
158 _this.lastOpenEventType = null;
159 return _this;
160 }
161
162 var _proto = Dropdown.prototype;
163
164 _proto.componentDidMount = function componentDidMount() {
165 this.focusNextOnOpen();
166 };
167
168 _proto.componentWillUpdate = function componentWillUpdate(nextProps) {
169 if (!nextProps.open && this.props.open) {
170 this._focusInDropdown = (0, _contains.default)(_reactDom.default.findDOMNode(this.menu), (0, _activeElement.default)(document));
171 }
172 };
173
174 _proto.componentDidUpdate = function componentDidUpdate(prevProps) {
175 var open = this.props.open;
176 var prevOpen = prevProps.open;
177
178 if (open && !prevOpen) {
179 this.focusNextOnOpen();
180 }
181
182 if (!open && prevOpen) {
183 // if focus hasn't already moved from the menu let's return it
184 // to the toggle
185 if (this._focusInDropdown) {
186 this._focusInDropdown = false;
187 this.focus();
188 }
189 }
190 };
191
192 _proto.focus = function focus() {
193 var toggle = _reactDom.default.findDOMNode(this.toggle);
194
195 if (toggle && toggle.focus) {
196 toggle.focus();
197 }
198 };
199
200 _proto.focusNextOnOpen = function focusNextOnOpen() {
201 var menu = this.menu;
202
203 if (!menu || !menu.focusNext) {
204 return;
205 }
206
207 if (this.lastOpenEventType === 'keydown' || this.props.role === 'menuitem') {
208 menu.focusNext();
209 }
210 };
211
212 _proto.handleClick = function handleClick(event) {
213 if (this.props.disabled) {
214 return;
215 }
216
217 this.toggleOpen(event, {
218 source: 'click'
219 });
220 };
221
222 _proto.handleClose = function handleClose(event, eventDetails) {
223 if (!this.props.open) {
224 return;
225 }
226
227 this.toggleOpen(event, eventDetails);
228 };
229
230 _proto.handleKeyDown = function handleKeyDown(event) {
231 if (this.props.disabled) {
232 return;
233 }
234
235 switch (event.keyCode) {
236 case _keycode.default.codes.down:
237 if (!this.props.open) {
238 this.toggleOpen(event, {
239 source: 'keydown'
240 });
241 } else if (this.menu.focusNext) {
242 this.menu.focusNext();
243 }
244
245 event.preventDefault();
246 break;
247
248 case _keycode.default.codes.esc:
249 case _keycode.default.codes.tab:
250 this.handleClose(event, {
251 source: 'keydown'
252 });
253 break;
254
255 default:
256 }
257 };
258
259 _proto.toggleOpen = function toggleOpen(event, eventDetails) {
260 var open = !this.props.open;
261
262 if (open) {
263 this.lastOpenEventType = eventDetails.source;
264 }
265
266 if (this.props.onToggle) {
267 this.props.onToggle(open, event, eventDetails);
268 }
269 };
270
271 _proto.renderMenu = function renderMenu(child, _ref) {
272 var _this2 = this;
273
274 var id = _ref.id,
275 onSelect = _ref.onSelect,
276 rootCloseEvent = _ref.rootCloseEvent,
277 props = (0, _objectWithoutPropertiesLoose2.default)(_ref, ["id", "onSelect", "rootCloseEvent"]);
278
279 var ref = function ref(c) {
280 _this2.menu = c;
281 };
282
283 if (typeof child.ref === 'string') {
284 process.env.NODE_ENV !== "production" ? (0, _warning.default)(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;
285 } else {
286 ref = (0, _createChainedFunction.default)(child.ref, ref);
287 }
288
289 return (0, _react.cloneElement)(child, (0, _extends2.default)({}, props, {
290 ref: ref,
291 labelledBy: id,
292 bsClass: (0, _bootstrapUtils.prefix)(props, 'menu'),
293 onClose: (0, _createChainedFunction.default)(child.props.onClose, this.handleClose),
294 onSelect: (0, _createChainedFunction.default)(child.props.onSelect, onSelect, function (key, event) {
295 return _this2.handleClose(event, {
296 source: 'select'
297 });
298 }),
299 rootCloseEvent: rootCloseEvent
300 }));
301 };
302
303 _proto.renderToggle = function renderToggle(child, props) {
304 var _this3 = this;
305
306 var ref = function ref(c) {
307 _this3.toggle = c;
308 };
309
310 if (typeof child.ref === 'string') {
311 process.env.NODE_ENV !== "production" ? (0, _warning.default)(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;
312 } else {
313 ref = (0, _createChainedFunction.default)(child.ref, ref);
314 }
315
316 return (0, _react.cloneElement)(child, (0, _extends2.default)({}, props, {
317 ref: ref,
318 bsClass: (0, _bootstrapUtils.prefix)(props, 'toggle'),
319 onClick: (0, _createChainedFunction.default)(child.props.onClick, this.handleClick),
320 onKeyDown: (0, _createChainedFunction.default)(child.props.onKeyDown, this.handleKeyDown)
321 }));
322 };
323
324 _proto.render = function render() {
325 var _classes,
326 _this4 = this;
327
328 var _this$props = this.props,
329 Component = _this$props.componentClass,
330 id = _this$props.id,
331 dropup = _this$props.dropup,
332 disabled = _this$props.disabled,
333 pullRight = _this$props.pullRight,
334 open = _this$props.open,
335 onSelect = _this$props.onSelect,
336 role = _this$props.role,
337 bsClass = _this$props.bsClass,
338 className = _this$props.className,
339 rootCloseEvent = _this$props.rootCloseEvent,
340 children = _this$props.children,
341 props = (0, _objectWithoutPropertiesLoose2.default)(_this$props, ["componentClass", "id", "dropup", "disabled", "pullRight", "open", "onSelect", "role", "bsClass", "className", "rootCloseEvent", "children"]);
342 delete props.onToggle;
343 var classes = (_classes = {}, _classes[bsClass] = true, _classes.open = open, _classes.disabled = disabled, _classes);
344
345 if (dropup) {
346 classes[bsClass] = false;
347 classes.dropup = true;
348 } // This intentionally forwards bsSize and bsStyle (if set) to the
349 // underlying component, to allow it to render size and style variants.
350
351
352 return _react.default.createElement(Component, (0, _extends2.default)({}, props, {
353 className: (0, _classnames.default)(className, classes)
354 }), _ValidComponentChildren.default.map(children, function (child) {
355 switch (child.props.bsRole) {
356 case TOGGLE_ROLE:
357 return _this4.renderToggle(child, {
358 id: id,
359 disabled: disabled,
360 open: open,
361 role: role,
362 bsClass: bsClass
363 });
364
365 case MENU_ROLE:
366 return _this4.renderMenu(child, {
367 id: id,
368 open: open,
369 pullRight: pullRight,
370 bsClass: bsClass,
371 onSelect: onSelect,
372 rootCloseEvent: rootCloseEvent
373 });
374
375 default:
376 return child;
377 }
378 }));
379 };
380
381 return Dropdown;
382}(_react.default.Component);
383
384Dropdown.propTypes = propTypes;
385Dropdown.defaultProps = defaultProps;
386(0, _bootstrapUtils.bsClass)('dropdown', Dropdown);
387var UncontrolledDropdown = (0, _uncontrollable.default)(Dropdown, {
388 open: 'onToggle'
389});
390UncontrolledDropdown.Toggle = _DropdownToggle.default;
391UncontrolledDropdown.Menu = _DropdownMenu.default;
392var _default = UncontrolledDropdown;
393exports.default = _default;
394module.exports = exports["default"];
\No newline at end of file