Skip to content

Commit fed65af

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

23 files changed

+4296
-51
lines changed

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: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
isHovered?: boolean;
14+
isActive?: boolean;
15+
isFocused?: boolean;
16+
position?: OneOf<typeof DropdownPosition, keyof typeof DropdownPosition>;
17+
direction?: OneOf<typeof DropdownDirection, keyof typeof DropdownDirection>;
18+
}
19+
20+
declare const OptionsMenu: FunctionComponent<OptionsMenuProps>;
21+
22+
export default OptionsMenu;
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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+
/** Forces display of the hover state of the Options menu */
23+
isHovered: PropTypes.bool,
24+
/** Forces display of the active state of the Options menu */
25+
isActive: PropTypes.bool,
26+
/** Forces display of the hover state of the Options menu */
27+
isFocused: PropTypes.bool,
28+
/** Display menu above or below Options menu toggle */
29+
direction: PropTypes.oneOf(Object.values(OptionsMenuDirection)),
30+
/** Indicates where menu will be aligned horizontally */
31+
position: PropTypes.oneOf(Object.values(OptionsMenuPosition)),
32+
};
33+
34+
const defaultProps = {
35+
className: '',
36+
title: '',
37+
isOpen: false,
38+
isPlain: false,
39+
isHovered: false,
40+
isActive: false,
41+
isFocused: false,
42+
direction: OptionsMenuDirection.down,
43+
position: OptionsMenuPosition.left,
44+
};
45+
46+
class OptionsMenu extends Component {
47+
48+
render() {
49+
const {
50+
className,
51+
direction,
52+
position,
53+
id,
54+
isOpen,
55+
isPlain,
56+
isHovered,
57+
isActive,
58+
isFocused,
59+
isText,
60+
title,
61+
menuItems,
62+
toggle } = this.props;
63+
return (
64+
<div id={id}
65+
className={
66+
css(styles.optionsMenu,
67+
direction === OptionsMenuDirection.up && getModifier(styles, 'top'),
68+
position === OptionsMenuPosition.right && getModifier(styles, 'align-right'),
69+
isOpen && getModifier(styles, 'expanded'),
70+
className)}>
71+
<span id={`${id}-label`} hidden>{title || id}</span>
72+
<div className={css(styles.optionsMenuToggle,
73+
isPlain && getModifier(styles, 'plain'),
74+
isHovered && getModifier(styles, 'hover'),
75+
isActive && getModifier(styles, 'active'),
76+
isFocused && getModifier(styles, 'focus'),
77+
isText && getModifier(styles, 'text')
78+
)}>
79+
{Children.map(toggle, oneToggle =>
80+
cloneElement(oneToggle, {
81+
parentId: id,
82+
isOpen,
83+
})
84+
)}
85+
</div>
86+
<ul className={css(styles.optionsMenuMenu,
87+
position === OptionsMenuPosition.right && getModifier(styles, 'align-right'))}
88+
aria-labelledby={`${id}-label`}
89+
hidden={!isOpen}>
90+
{menuItems.map((item) => {
91+
return <li key={item.key}>{item}</li>
92+
})}
93+
</ul>
94+
</div>
95+
)
96+
}
97+
}
98+
99+
OptionsMenu.propTypes = propTypes;
100+
OptionsMenu.defaultProps = defaultProps;
101+
102+
export default OptionsMenu;

0 commit comments

Comments
 (0)