Vulcan/packages/vulcan-ui-bootstrap/lib/components/ui/Dropdown.jsx

103 lines
3.3 KiB
React
Raw Normal View History

2018-04-24 10:20:38 +09:00
import React from 'react';
2018-05-04 11:56:19 +09:00
import PropTypes from 'prop-types';
2018-04-24 10:20:38 +09:00
import { registerComponent } from 'meteor/vulcan:lib';
import Dropdown from 'react-bootstrap/lib/Dropdown';
import MenuItem from 'react-bootstrap/lib/MenuItem';
import DropdownButton from 'react-bootstrap/lib/DropdownButton';
import { LinkContainer } from 'react-router-bootstrap';
2018-05-04 11:56:19 +09:00
import { FormattedMessage } from 'meteor/vulcan:i18n';
2018-04-24 10:20:38 +09:00
/*
2018-05-04 11:56:19 +09:00
A node contains a menu item, and optionally a list of child items
*/
const Node = ({ childrenItems, ...rest }) => {
return (
<div className="menu-node">
<Item {...rest} />
{childrenItems &&
!!childrenItems.length && (
<div className="menu-node-children">{childrenItems.map((item, index) => <Item key={index} {...item} />)}</div>
)}
</div>
);
};
Node.propTypes = {
childrenItems: PropTypes.array, // an array of dropdown items used as children of the current item
};
/*
Note: `rest` is used to ensure auto-generated props from parent dropdown
2018-04-24 10:20:38 +09:00
components are properly passed down to MenuItem
*/
2018-05-04 11:56:19 +09:00
const Item = ({ index, to, labelId, label, component, componentProps = {}, itemProps, ...rest }) => {
let menuComponent;
if (component) {
2018-05-10 17:48:22 +09:00
menuComponent = React.cloneElement(component, componentProps);
2018-05-04 11:56:19 +09:00
} else if (labelId) {
menuComponent = <FormattedMessage id={labelId} />;
} else {
menuComponent = <span>{label}</span>;
}
2018-04-24 10:20:38 +09:00
const item = (
2018-05-04 11:56:19 +09:00
<MenuItem className="dropdown-item" eventKey={index} {...itemProps} {...rest}>
{menuComponent}
2018-04-24 10:20:38 +09:00
</MenuItem>
);
2018-05-04 11:56:19 +09:00
2018-04-24 10:20:38 +09:00
return to ? <LinkContainer to={to}>{item}</LinkContainer> : item;
};
2018-05-04 11:56:19 +09:00
Item.propTypes = {
index: PropTypes.number, // index
to: PropTypes.any, // a string or object, used to generate the router path for the menu item
id: PropTypes.string, // an i18n id for the item label
label: PropTypes.string, // item label string, used if id is not provided
component: PropTypes.object, // a component to use as menu item
componentProps: PropTypes.object, // props passed to the component
itemProps: PropTypes.object, // props for the <MenuItem/> component
};
2018-04-24 10:20:38 +09:00
2018-05-04 11:56:19 +09:00
const BootstrapDropdown = ({ label, labelId, trigger, menuItems, menuContents, ...dropdownProps }) => {
const menuBody = menuContents ? menuContents : menuItems.map((item, index) => {
2018-04-24 10:20:38 +09:00
if (item === 'divider') {
return <MenuItem divider key={index} />;
} else {
2018-05-04 11:56:19 +09:00
return <Node {...item} key={index} index={index} />;
2018-04-24 10:20:38 +09:00
}
});
if (trigger) {
// if a trigger component has been provided, use it
return (
<Dropdown {...dropdownProps}>
<Dropdown.Toggle>{trigger}</Dropdown.Toggle>
2018-05-04 11:56:19 +09:00
<Dropdown.Menu>{menuBody}</Dropdown.Menu>
2018-04-24 10:20:38 +09:00
</Dropdown>
);
} else {
// else default to DropdownButton
return (
2018-05-04 11:56:19 +09:00
<DropdownButton title={labelId ? <FormattedMessage id={labelId} /> : label} {...dropdownProps}>
{menuBody}
2018-04-24 10:20:38 +09:00
</DropdownButton>
);
}
};
2018-05-04 11:56:19 +09:00
BootstrapDropdown.propTypes = {
labelId: PropTypes.string, // menu title/label i18n string
label: PropTypes.string, // menu title/label
trigger: PropTypes.object, // component used as menu trigger (the part you click to open the menu)
menuContents: PropTypes.object, // a component specifying the menu contents
menuItems: PropTypes.array, // an array of menu items, used if menuContents is not provided
};
2018-04-24 10:20:38 +09:00
registerComponent('Dropdown', BootstrapDropdown);