Web:Components:MenuItem: add arrow type
This commit is contained in:
parent
853037c00d
commit
cad4948cab
@ -2,26 +2,107 @@ import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { ReactSVG } from "react-svg";
|
||||
|
||||
import DomHelpers from "../utils/domHelpers";
|
||||
|
||||
import { isMobile } from "react-device-detect";
|
||||
import {
|
||||
isTablet as isTabletUtils,
|
||||
isMobile as isMobileUtils,
|
||||
} from "../utils/device";
|
||||
|
||||
import { StyledMenuItem, StyledText, IconWrapper } from "./styled-menu-item";
|
||||
|
||||
import ArrowIcon from "./svg/folder-arrow.react.svg";
|
||||
import ArrowMobileIcon from "./svg/folder-arrow.mobile.react.svg";
|
||||
import NewContextMenu from "../new-context-menu";
|
||||
|
||||
//TODO: Add arrow type
|
||||
const MenuItem = (props) => {
|
||||
const [hover, setHover] = React.useState(false);
|
||||
const [positionContextMenu, setPositionContextMenu] = React.useState(null);
|
||||
const itemRef = React.useRef(null);
|
||||
const cmRef = React.useRef(null);
|
||||
//console.log("MenuItem render");
|
||||
const {
|
||||
isHeader,
|
||||
isSeparator,
|
||||
label,
|
||||
icon,
|
||||
options,
|
||||
children,
|
||||
onClick,
|
||||
className,
|
||||
} = props;
|
||||
|
||||
const onHover = () => {
|
||||
if (!cmRef.current) return;
|
||||
if (hover) {
|
||||
getPosition();
|
||||
cmRef.current.show(new Event("click"));
|
||||
} else {
|
||||
cmRef.current.hide(new Event("click"));
|
||||
}
|
||||
};
|
||||
|
||||
const getPosition = () => {
|
||||
if (!cmRef.current) return;
|
||||
if (!itemRef.current) return;
|
||||
const outerWidth = DomHelpers.getOuterWidth(itemRef.current);
|
||||
const offset = DomHelpers.getOffset(itemRef.current);
|
||||
|
||||
setPositionContextMenu({
|
||||
top: offset.top,
|
||||
left: offset.left + outerWidth + 10,
|
||||
width: outerWidth,
|
||||
});
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
onHover();
|
||||
}, [hover]);
|
||||
|
||||
const onClickAction = (e) => {
|
||||
onClick && onClick(e);
|
||||
};
|
||||
|
||||
return (
|
||||
return options ? (
|
||||
<StyledMenuItem
|
||||
{...props}
|
||||
className={className}
|
||||
onClick={onClickAction}
|
||||
ref={itemRef}
|
||||
onMouseEnter={() => setHover(true)}
|
||||
onMouseLeave={() => setHover(false)}
|
||||
>
|
||||
{icon && (
|
||||
<IconWrapper isHeader={isHeader}>
|
||||
<ReactSVG src={icon} className="drop-down-item_icon" />
|
||||
</IconWrapper>
|
||||
)}
|
||||
{isSeparator ? (
|
||||
<></>
|
||||
) : label ? (
|
||||
<>
|
||||
<StyledText isHeader={isHeader} truncate={true}>
|
||||
{label}
|
||||
</StyledText>
|
||||
{isMobile || isTabletUtils() || isMobileUtils() ? (
|
||||
<ArrowMobileIcon className="arrow-icon" />
|
||||
) : (
|
||||
<ArrowIcon className="arrow-icon" />
|
||||
)}
|
||||
<NewContextMenu
|
||||
ref={cmRef}
|
||||
model={options}
|
||||
withBackdrop={false}
|
||||
position={positionContextMenu}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
children && children
|
||||
)}
|
||||
</StyledMenuItem>
|
||||
) : (
|
||||
<StyledMenuItem {...props} className={className} onClick={onClickAction}>
|
||||
{icon && (
|
||||
<IconWrapper isHeader={isHeader}>
|
||||
@ -31,9 +112,11 @@ const MenuItem = (props) => {
|
||||
{isSeparator ? (
|
||||
<></>
|
||||
) : label ? (
|
||||
<>
|
||||
<StyledText isHeader={isHeader} truncate={true}>
|
||||
{label}
|
||||
</StyledText>
|
||||
</>
|
||||
) : (
|
||||
children && children
|
||||
)}
|
||||
@ -48,10 +131,12 @@ MenuItem.propTypes = {
|
||||
isHeader: PropTypes.bool,
|
||||
/** Accepts tab-index */
|
||||
tabIndex: PropTypes.number,
|
||||
/** menu item text */
|
||||
/** Menu item text */
|
||||
label: PropTypes.string,
|
||||
/** menu item icon */
|
||||
/** Menu item icon */
|
||||
icon: PropTypes.string,
|
||||
/** Tells when the menu item should display like arrow and open context menu */
|
||||
options: PropTypes.array,
|
||||
/** Disable default style hover effect */
|
||||
noHover: PropTypes.bool,
|
||||
/** What the menu item will trigger when clicked */
|
||||
|
@ -45,6 +45,25 @@ const Template = () => {
|
||||
<MenuItem onClick={() => console.log("Button 3 clicked")}>
|
||||
<div>some child without styles</div>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon={"static/images/nav.logo.react.svg"}
|
||||
label="Item after separator"
|
||||
options={[
|
||||
{
|
||||
key: "key1",
|
||||
icon: "static/images/nav.logo.react.svg",
|
||||
label: "Item after separator",
|
||||
onClick: () => console.log("Button 1 clicked"),
|
||||
},
|
||||
{
|
||||
key: "key2",
|
||||
icon: "static/images/nav.logo.react.svg",
|
||||
label: "Item after separator",
|
||||
onClick: () => console.log("Button 2 clicked"),
|
||||
},
|
||||
]}
|
||||
onClick={() => console.log("Button 2 clicked")}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -17,6 +17,7 @@ const styledMobileText = css`
|
||||
`;
|
||||
|
||||
const StyledText = styled(Text)`
|
||||
width: 100%;
|
||||
font-weight: ${(props) => props.theme.menuItem.text.fontWeight};
|
||||
font-size: ${(props) => props.theme.menuItem.text.fontSize};
|
||||
line-height: ${(props) => props.theme.menuItem.text.lineHeight};
|
||||
@ -125,6 +126,10 @@ const StyledMenuItem = styled.div`
|
||||
cursor: default !important;
|
||||
}
|
||||
`}
|
||||
|
||||
.arrow-icon {
|
||||
margin: 0 0 0 8px;
|
||||
}
|
||||
`;
|
||||
StyledMenuItem.defaultProps = { theme: Base };
|
||||
|
||||
|
@ -29,6 +29,7 @@ and header(show only tablet or mobile, when view changed).
|
||||
| `id` | `string` | - | - | `contextMenu` | Accepts id |
|
||||
| `model` | `array` | - | - | `[]` | Items collection |
|
||||
| `header` | `object` | - | - | `{}` | ContextMenu header |
|
||||
| `position` | `object` | - | - | `{}` | ContextMenu position |
|
||||
| `style` | `obj`, `array` | - | - | - | Accepts css style |
|
||||
| `targetAreaId` | `string` | - | - | - | Id of container apply to |
|
||||
| `withBackdrop` | `bool` | - | - | `true` | Used to display backdrop |
|
||||
|
@ -33,6 +33,8 @@ const Row = React.memo(({ data, index, style }) => {
|
||||
// eslint-disable-next-line react/prop-types
|
||||
isSeparator={data[index].isSeparator}
|
||||
// eslint-disable-next-line react/prop-types
|
||||
options={data[index].options}
|
||||
// eslint-disable-next-line react/prop-types
|
||||
onClick={data[index].onClick}
|
||||
style={style}
|
||||
/>
|
||||
@ -146,6 +148,25 @@ class NewContextMenu extends React.Component {
|
||||
}
|
||||
|
||||
position(event) {
|
||||
if (this.props.position) {
|
||||
let width = this.menuRef.current.offsetParent
|
||||
? this.menuRef.current.offsetWidth
|
||||
: DomHelpers.getHiddenElementOuterWidth(this.menuRef.current);
|
||||
let viewport = DomHelpers.getViewport();
|
||||
if (
|
||||
this.props.position.left + width >
|
||||
viewport.width - DomHelpers.calculateScrollbarWidth()
|
||||
) {
|
||||
this.menuRef.current.style.right =
|
||||
// -1 * this.props.position.width + width + "px";
|
||||
0 + "px";
|
||||
} else {
|
||||
this.menuRef.current.style.left = this.props.position.left + "px";
|
||||
}
|
||||
|
||||
this.menuRef.current.style.top = this.props.position.top + "px";
|
||||
return;
|
||||
}
|
||||
if (event) {
|
||||
let left = event.pageX + 1;
|
||||
let top = event.pageY + 1;
|
||||
@ -343,6 +364,7 @@ class NewContextMenu extends React.Component {
|
||||
icon={item.icon}
|
||||
label={item.label}
|
||||
isSeparator={item.isSeparator}
|
||||
options={item.options}
|
||||
onClick={item.onClick}
|
||||
/>
|
||||
);
|
||||
@ -356,10 +378,11 @@ class NewContextMenu extends React.Component {
|
||||
const className = classNames("p-contextmenu", this.props.className);
|
||||
|
||||
const items = this.renderContextMenuItems();
|
||||
|
||||
return (
|
||||
<>
|
||||
{this.props.withBackdrop && (
|
||||
<Backdrop visible={this.state.visible} withBackground={true} />
|
||||
)}
|
||||
<StyledContextMenu changeView={this.state.changeView}>
|
||||
<CSSTransition
|
||||
nodeRef={this.menuRef}
|
||||
@ -406,16 +429,20 @@ class NewContextMenu extends React.Component {
|
||||
NewContextMenu.propTypes = {
|
||||
/** Unique identifier of the element */
|
||||
id: PropTypes.string,
|
||||
/** An array of menuitems */
|
||||
/** An array of objects */
|
||||
model: PropTypes.array,
|
||||
/** An object of header */
|
||||
/** An object of header with icon and label */
|
||||
header: PropTypes.object,
|
||||
/** Position of context menu */
|
||||
position: PropTypes.object,
|
||||
/** Inline style of the component */
|
||||
style: PropTypes.object,
|
||||
/** Style class of the component */
|
||||
className: PropTypes.string,
|
||||
/** Attaches the menu to document instead of a particular item */
|
||||
global: PropTypes.bool,
|
||||
/** Tell when context menu was render with backdrop */
|
||||
withBackdrop: PropTypes.bool,
|
||||
/** Base zIndex value to use in layering */
|
||||
autoZIndex: PropTypes.bool,
|
||||
/** Whether to automatically manage layering */
|
||||
@ -431,6 +458,8 @@ NewContextMenu.propTypes = {
|
||||
NewContextMenu.defaultProps = {
|
||||
id: null,
|
||||
model: null,
|
||||
position: null,
|
||||
header: null,
|
||||
style: null,
|
||||
className: null,
|
||||
global: false,
|
||||
@ -439,6 +468,7 @@ NewContextMenu.defaultProps = {
|
||||
appendTo: null,
|
||||
onShow: null,
|
||||
onHide: null,
|
||||
withBackdrop: true,
|
||||
};
|
||||
|
||||
export default NewContextMenu;
|
||||
|
@ -110,6 +110,20 @@ const Template = (args) => {
|
||||
icon: "/static/images/catalog.shared.react.svg",
|
||||
key: "sharing-settings10",
|
||||
label: "Sharing settings",
|
||||
options: [
|
||||
{
|
||||
key: "key1",
|
||||
icon: "static/images/nav.logo.react.svg",
|
||||
label: "Item after separator",
|
||||
onClick: () => console.log("Button 1 clicked"),
|
||||
},
|
||||
{
|
||||
key: "key2",
|
||||
icon: "static/images/nav.logo.react.svg",
|
||||
label: "Item after separator",
|
||||
onClick: () => console.log("Button 2 clicked"),
|
||||
},
|
||||
],
|
||||
onClick: () => console.log("item 3 clicked"),
|
||||
},
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user