Extract `Menu` component from `ConnectedAccountsListOptions` (#8632)
A `Menu` component has been extracted from the `ConnectedAccountsListOptions` component. The menu and the menu items are now the `Menu` and `MenuItem` components respectively. A custom body was added to the Storybook preview to ensure that the `popover-content` element was present in the DOM before the Menu was constructed.feature/default_network_editable
parent
91953f062b
commit
f886686db2
@ -0,0 +1,2 @@ |
||||
<div id="custom-root"></div> |
||||
<div id="popover-content"></div> |
@ -1,26 +0,0 @@ |
||||
import classnames from 'classnames' |
||||
import PropTypes from 'prop-types' |
||||
import React, { PureComponent } from 'react' |
||||
|
||||
export default class ConnectedAccountsListOptionsItem extends PureComponent { |
||||
static propTypes = { |
||||
iconClassNames: PropTypes.string.isRequired, |
||||
children: PropTypes.node.isRequired, |
||||
onClick: PropTypes.func, |
||||
} |
||||
|
||||
static defaultProps = { |
||||
onClick: undefined, |
||||
} |
||||
|
||||
render () { |
||||
const { children, iconClassNames, onClick } = this.props |
||||
|
||||
return ( |
||||
<button className="connected-accounts-options__row" onClick={onClick}> |
||||
<i className={classnames('connected-accounts-options__row-icon', iconClassNames)} /> |
||||
<span>{children}</span> |
||||
</button> |
||||
) |
||||
} |
||||
} |
@ -1 +0,0 @@ |
||||
export { default } from './connected-accounts-list-options-item.component' |
@ -0,0 +1,2 @@ |
||||
export { default as Menu } from './menu' |
||||
export { default as MenuItem } from './menu-item' |
@ -0,0 +1,31 @@ |
||||
import React from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import classnames from 'classnames' |
||||
|
||||
const MenuItem = ({ children, className, iconClassName, onClick }) => ( |
||||
<button className={classnames('menu-item', className)} onClick={onClick}> |
||||
{ |
||||
iconClassName |
||||
? ( |
||||
<i className={classnames('menu-item__icon', iconClassName)} /> |
||||
) |
||||
: null |
||||
} |
||||
<span>{children}</span> |
||||
</button> |
||||
) |
||||
|
||||
MenuItem.propTypes = { |
||||
children: PropTypes.node.isRequired, |
||||
className: PropTypes.string, |
||||
iconClassName: PropTypes.string, |
||||
onClick: PropTypes.func, |
||||
} |
||||
|
||||
MenuItem.defaultProps = { |
||||
className: undefined, |
||||
iconClassName: undefined, |
||||
onClick: undefined, |
||||
} |
||||
|
||||
export default MenuItem |
@ -0,0 +1,43 @@ |
||||
import PropTypes from 'prop-types' |
||||
import React, { useRef, useState } from 'react' |
||||
import { createPortal } from 'react-dom' |
||||
import { usePopper } from 'react-popper' |
||||
import classnames from 'classnames' |
||||
|
||||
const Menu = ({ anchorElement, children, className, onHide, popperOptions }) => { |
||||
const [popperElement, setPopperElement] = useState(null) |
||||
const popoverContainerElement = useRef(document.getElementById('popover-content')) |
||||
|
||||
const { attributes, styles } = usePopper(anchorElement, popperElement, popperOptions) |
||||
|
||||
return createPortal( |
||||
<> |
||||
<div className="menu__background" onClick={onHide} /> |
||||
<div |
||||
className={classnames('menu__container', className)} |
||||
ref={setPopperElement} |
||||
style={styles.popper} |
||||
{...attributes.popper} |
||||
> |
||||
{ children } |
||||
</div> |
||||
</>, |
||||
popoverContainerElement.current |
||||
) |
||||
} |
||||
|
||||
Menu.propTypes = { |
||||
anchorElement: PropTypes.instanceOf(window.Element), |
||||
children: PropTypes.node.isRequired, |
||||
className: PropTypes.string, |
||||
onHide: PropTypes.func.isRequired, |
||||
popperOptions: PropTypes.object, |
||||
} |
||||
|
||||
Menu.defaultProps = { |
||||
anchorElement: undefined, |
||||
className: undefined, |
||||
popperOptions: undefined, |
||||
} |
||||
|
||||
export default Menu |
@ -0,0 +1,46 @@ |
||||
.menu { |
||||
&__container { |
||||
background: $white; |
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.214); |
||||
border-radius: 8px; |
||||
width: 225px; |
||||
color: $Black-100; |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
padding: 0 16px; |
||||
|
||||
font-family: Roboto, 'sans-serif'; |
||||
font-size: 14px; |
||||
font-weight: normal; |
||||
line-height: 20px; |
||||
|
||||
z-index: 1050; |
||||
} |
||||
|
||||
&__background { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
width: 100vw; |
||||
height: 100vh; |
||||
z-index: 1050; |
||||
} |
||||
} |
||||
|
||||
.menu-item { |
||||
background: none; |
||||
font-family: inherit; |
||||
font-size: inherit; |
||||
|
||||
display: flex; |
||||
flex-direction: row; |
||||
align-items: center; |
||||
width: 100%; |
||||
padding: 14px 0; |
||||
cursor: pointer; |
||||
|
||||
&__icon { |
||||
margin-right: 8px; |
||||
} |
||||
} |
@ -0,0 +1,36 @@ |
||||
import React, { useState } from 'react' |
||||
import { Menu, MenuItem } from '.' |
||||
import { action } from '@storybook/addon-actions' |
||||
|
||||
export default { |
||||
title: 'Menu', |
||||
} |
||||
|
||||
export const basic = () => { |
||||
return ( |
||||
<Menu |
||||
onHide={action('Hide')} |
||||
> |
||||
<MenuItem iconClassName="fas fa-bullseye" onClick={action('Menu Item 1')}>Menu Item 1</MenuItem> |
||||
<MenuItem onClick={action('Menu Item 2')}>Menu Item 2</MenuItem> |
||||
<MenuItem iconClassName="fas fa-bold" onClick={action('Menu Item 3')}>Menu Item 3</MenuItem> |
||||
</Menu> |
||||
) |
||||
} |
||||
|
||||
export const anchored = () => { |
||||
const [anchorElement, setAnchorElement] = useState(null) |
||||
return ( |
||||
<> |
||||
<button ref={setAnchorElement}>Menu</button> |
||||
<Menu |
||||
anchorElement={anchorElement} |
||||
onHide={action('Hide')} |
||||
> |
||||
<MenuItem iconClassName="fas fa-bullseye" onClick={action('Menu Item 1')}>Menu Item 1</MenuItem> |
||||
<MenuItem onClick={action('Menu Item 2')}>Menu Item 2</MenuItem> |
||||
<MenuItem iconClassName="fas fa-bold" onClick={action('Menu Item 3')}>Menu Item 3</MenuItem> |
||||
</Menu> |
||||
</> |
||||
) |
||||
} |
Loading…
Reference in new issue