Skip to content

Commit 21fdda7

Browse files
committed
Feat(Options Menu): Add Options Menu Component
1 parent 202490c commit 21fdda7

26 files changed

Lines changed: 2398 additions & 52 deletions

packages/patternfly-4/react-core/src/components/Dropdown/Dropdown.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const propTypes = {
2626
isOpen: PropTypes.bool,
2727
/** Display the toggle with no border or background */
2828
isPlain: PropTypes.bool,
29-
/** Indicates where menu will be alligned horizontally */
29+
/** Indicates where menu will be aligned horizontally */
3030
position: PropTypes.oneOf(Object.values(DropdownPosition)),
3131
/** Display menu above or below dropdown toggle */
3232
direction: PropTypes.oneOf(Object.values(DropdownDirection)),
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { FunctionComponent, HTMLProps, ReactNode } from 'react';
2+
import { DropdownDirection, DropdownPosition } from '../Dropdown';
3+
import { OneOf } from '../../helpers';
4+
5+
export interface OptionsMenuProps extends HTMLProps<HTMLDivElement> {
6+
className?: string;
7+
id: string;
8+
menuItems: ReactNode[];
9+
toggle: ReactNode;
10+
isPlain?: boolean;
11+
isOpen?: boolean;
12+
ariaLabelMenu?: string;
13+
position?: OneOf<typeof DropdownPosition, keyof typeof DropdownPosition>;
14+
direction?: OneOf<typeof DropdownDirection, keyof typeof DropdownDirection>;
15+
}
16+
17+
declare const OptionsMenu: FunctionComponent<OptionsMenuProps>;
18+
19+
export default OptionsMenu;
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import React, { Children, cloneElement, Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
import styles from '@patternfly/patternfly/components/OptionsMenu/options-menu.css';
4+
import { css, getModifier } from '@patternfly/react-styles';
5+
import { OptionsMenuDirection, OptionsMenuPosition } from './optionsMenuConstants';
6+
7+
const propTypes = {
8+
/** Classes applied to root element of the Options menu */
9+
className: PropTypes.string,
10+
/** Id of the root element of the Options menu */
11+
id: PropTypes.string.isRequired,
12+
/** Array of OptionsMenuItem and/or OptionMenuItemGroup nodes that will be rendered in the Options menu list */
13+
menuItems: PropTypes.arrayOf(PropTypes.node).isRequired,
14+
/** Either an OptionsMenuToggle or an OptionsMenuToggleWithText to use to toggle the Options menu */
15+
toggle: PropTypes.node.isRequired,
16+
/** Flag to indicate if menu is open */
17+
isOpen: PropTypes.bool,
18+
/** Flag to indicate the toggle has no border or background */
19+
isPlain: PropTypes.bool,
20+
/** Provides an accessible name for the Options menu */
21+
ariaLabelMenu: PropTypes.string,
22+
/** Display menu above or below Options menu toggle */
23+
direction: PropTypes.oneOf(Object.values(OptionsMenuDirection)),
24+
/** Indicates where menu will be aligned horizontally */
25+
position: PropTypes.oneOf(Object.values(OptionsMenuPosition)),
26+
};
27+
28+
const defaultProps = {
29+
className: '',
30+
isOpen: false,
31+
isPlain: false,
32+
ariaLabelMenu: '',
33+
direction: OptionsMenuDirection.down,
34+
position: OptionsMenuPosition.left,
35+
};
36+
37+
class OptionsMenu extends Component {
38+
39+
render() {
40+
const {
41+
className,
42+
direction,
43+
position,
44+
id,
45+
isOpen,
46+
isPlain,
47+
ariaLabelMenu,
48+
menuItems,
49+
toggle } = this.props;
50+
return (
51+
<div id={id}
52+
className={
53+
css(styles.optionsMenu,
54+
direction === OptionsMenuDirection.up && getModifier(styles, 'top'),
55+
position === OptionsMenuPosition.right && getModifier(styles, 'align-right'),
56+
isOpen && getModifier(styles, 'expanded'),
57+
className)}>
58+
{Children.map(toggle, oneToggle =>
59+
cloneElement(oneToggle, {
60+
parentId: id,
61+
isOpen,
62+
isPlain,
63+
}))}
64+
{isOpen &&
65+
<ul className={css(styles.optionsMenuMenu,
66+
position === OptionsMenuPosition.right && getModifier(styles, 'align-right'))}
67+
{...ariaLabelMenu ? {'aria-label': ariaLabelMenu} : {'aria-labelledby': `${id}-toggle`}}>
68+
{menuItems.map((item) => {
69+
if (item.type.displayName === 'OptionsMenuSeparator') {
70+
return item;
71+
}
72+
return <li key={item.key}>{item}</li>
73+
})}
74+
</ul>}
75+
</div>
76+
)
77+
}
78+
}
79+
80+
OptionsMenu.propTypes = propTypes;
81+
OptionsMenu.defaultProps = defaultProps;
82+
83+
export default OptionsMenu;

0 commit comments

Comments
 (0)