Skip to content

Commit 99e44c0

Browse files
committed
Feat(Options Menu): Add Options Menu Component
1 parent 9b14bd3 commit 99e44c0

24 files changed

Lines changed: 4329 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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
title: string,
11+
isPlain?: boolean;
12+
isOpen?: boolean;
13+
isText?: boolean;
14+
position?: OneOf<typeof DropdownPosition, keyof typeof DropdownPosition>;
15+
direction?: OneOf<typeof DropdownDirection, keyof typeof DropdownDirection>;
16+
}
17+
18+
declare const OptionsMenu: FunctionComponent<OptionsMenuProps>;
19+
20+
export default OptionsMenu;
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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 OptionsMenuToggleButton or a custom button to use to toggle the Options menu */
15+
toggle: PropTypes.node.isRequired,
16+
/** Provides an accessible name for the Options menu */
17+
title: PropTypes.string,
18+
/** Flag to indicate if menu is open */
19+
isOpen: PropTypes.bool,
20+
/** Flag to indicate the toggle has no border or background */
21+
isPlain: PropTypes.bool,
22+
/** For use when the .pf-c-options-menu__toggle is a <div> or some non-interactive elment, and you're using a custom .pf-c-options-menu__toggle-button to toggle the options menu. */
23+
isText: PropTypes.bool,
24+
/** Display menu above or below Options menu toggle */
25+
direction: PropTypes.oneOf(Object.values(OptionsMenuDirection)),
26+
/** Indicates where menu will be aligned horizontally */
27+
position: PropTypes.oneOf(Object.values(OptionsMenuPosition)),
28+
};
29+
30+
const defaultProps = {
31+
className: '',
32+
title: '',
33+
isOpen: false,
34+
isPlain: false,
35+
isText: false,
36+
direction: OptionsMenuDirection.down,
37+
position: OptionsMenuPosition.left,
38+
};
39+
40+
class OptionsMenu extends Component {
41+
42+
render() {
43+
const {
44+
className,
45+
direction,
46+
position,
47+
id,
48+
isOpen,
49+
isPlain,
50+
isText,
51+
title,
52+
menuItems,
53+
toggle } = this.props;
54+
return (
55+
<div id={id}
56+
className={
57+
css(styles.optionsMenu,
58+
direction === OptionsMenuDirection.up && getModifier(styles, 'top'),
59+
position === OptionsMenuPosition.right && getModifier(styles, 'align-right'),
60+
isOpen && getModifier(styles, 'expanded'),
61+
className)}>
62+
<span id={`${id}-label`} hidden>{title || id}</span>
63+
{isText ? (
64+
<div className={css(styles.optionsMenuToggle, isPlain && getModifier(styles, 'plain'))}>{toggle}</div>
65+
) : (Children.map(toggle, oneToggle =>
66+
cloneElement(oneToggle, {
67+
parentId: id,
68+
isOpen,
69+
isPlain,
70+
})))
71+
}
72+
<ul className={css(styles.optionsMenuMenu,
73+
position === OptionsMenuPosition.right && getModifier(styles, 'align-right'))}
74+
aria-labelledby={`${id}-label`}
75+
hidden={!isOpen}>
76+
{menuItems.map((item) => {
77+
if (item.type.displayName === "OptionsMenuSeparator") {
78+
return item;
79+
}
80+
return <li key={item.key}>{item}</li>
81+
})}
82+
</ul>
83+
</div>
84+
)
85+
}
86+
}
87+
88+
OptionsMenu.propTypes = propTypes;
89+
OptionsMenu.defaultProps = defaultProps;
90+
91+
export default OptionsMenu;

0 commit comments

Comments
 (0)