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 PropTypes from "prop-types";
|
||||||
import { ReactSVG } from "react-svg";
|
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 { 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
|
//TODO: Add arrow type
|
||||||
const MenuItem = (props) => {
|
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");
|
//console.log("MenuItem render");
|
||||||
const {
|
const {
|
||||||
isHeader,
|
isHeader,
|
||||||
isSeparator,
|
isSeparator,
|
||||||
label,
|
label,
|
||||||
icon,
|
icon,
|
||||||
|
options,
|
||||||
children,
|
children,
|
||||||
onClick,
|
onClick,
|
||||||
className,
|
className,
|
||||||
} = props;
|
} = 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) => {
|
const onClickAction = (e) => {
|
||||||
onClick && onClick(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}>
|
<StyledMenuItem {...props} className={className} onClick={onClickAction}>
|
||||||
{icon && (
|
{icon && (
|
||||||
<IconWrapper isHeader={isHeader}>
|
<IconWrapper isHeader={isHeader}>
|
||||||
@ -31,9 +112,11 @@ const MenuItem = (props) => {
|
|||||||
{isSeparator ? (
|
{isSeparator ? (
|
||||||
<></>
|
<></>
|
||||||
) : label ? (
|
) : label ? (
|
||||||
|
<>
|
||||||
<StyledText isHeader={isHeader} truncate={true}>
|
<StyledText isHeader={isHeader} truncate={true}>
|
||||||
{label}
|
{label}
|
||||||
</StyledText>
|
</StyledText>
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
children && children
|
children && children
|
||||||
)}
|
)}
|
||||||
@ -48,10 +131,12 @@ MenuItem.propTypes = {
|
|||||||
isHeader: PropTypes.bool,
|
isHeader: PropTypes.bool,
|
||||||
/** Accepts tab-index */
|
/** Accepts tab-index */
|
||||||
tabIndex: PropTypes.number,
|
tabIndex: PropTypes.number,
|
||||||
/** menu item text */
|
/** Menu item text */
|
||||||
label: PropTypes.string,
|
label: PropTypes.string,
|
||||||
/** menu item icon */
|
/** Menu item icon */
|
||||||
icon: PropTypes.string,
|
icon: PropTypes.string,
|
||||||
|
/** Tells when the menu item should display like arrow and open context menu */
|
||||||
|
options: PropTypes.array,
|
||||||
/** Disable default style hover effect */
|
/** Disable default style hover effect */
|
||||||
noHover: PropTypes.bool,
|
noHover: PropTypes.bool,
|
||||||
/** What the menu item will trigger when clicked */
|
/** What the menu item will trigger when clicked */
|
||||||
|
@ -45,6 +45,25 @@ const Template = () => {
|
|||||||
<MenuItem onClick={() => console.log("Button 3 clicked")}>
|
<MenuItem onClick={() => console.log("Button 3 clicked")}>
|
||||||
<div>some child without styles</div>
|
<div>some child without styles</div>
|
||||||
</MenuItem>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -17,6 +17,7 @@ const styledMobileText = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledText = styled(Text)`
|
const StyledText = styled(Text)`
|
||||||
|
width: 100%;
|
||||||
font-weight: ${(props) => props.theme.menuItem.text.fontWeight};
|
font-weight: ${(props) => props.theme.menuItem.text.fontWeight};
|
||||||
font-size: ${(props) => props.theme.menuItem.text.fontSize};
|
font-size: ${(props) => props.theme.menuItem.text.fontSize};
|
||||||
line-height: ${(props) => props.theme.menuItem.text.lineHeight};
|
line-height: ${(props) => props.theme.menuItem.text.lineHeight};
|
||||||
@ -125,6 +126,10 @@ const StyledMenuItem = styled.div`
|
|||||||
cursor: default !important;
|
cursor: default !important;
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
|
|
||||||
|
.arrow-icon {
|
||||||
|
margin: 0 0 0 8px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
StyledMenuItem.defaultProps = { theme: Base };
|
StyledMenuItem.defaultProps = { theme: Base };
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ and header(show only tablet or mobile, when view changed).
|
|||||||
| `id` | `string` | - | - | `contextMenu` | Accepts id |
|
| `id` | `string` | - | - | `contextMenu` | Accepts id |
|
||||||
| `model` | `array` | - | - | `[]` | Items collection |
|
| `model` | `array` | - | - | `[]` | Items collection |
|
||||||
| `header` | `object` | - | - | `{}` | ContextMenu header |
|
| `header` | `object` | - | - | `{}` | ContextMenu header |
|
||||||
|
| `position` | `object` | - | - | `{}` | ContextMenu position |
|
||||||
| `style` | `obj`, `array` | - | - | - | Accepts css style |
|
| `style` | `obj`, `array` | - | - | - | Accepts css style |
|
||||||
| `targetAreaId` | `string` | - | - | - | Id of container apply to |
|
| `targetAreaId` | `string` | - | - | - | Id of container apply to |
|
||||||
| `withBackdrop` | `bool` | - | - | `true` | Used to display backdrop |
|
| `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
|
// eslint-disable-next-line react/prop-types
|
||||||
isSeparator={data[index].isSeparator}
|
isSeparator={data[index].isSeparator}
|
||||||
// eslint-disable-next-line react/prop-types
|
// eslint-disable-next-line react/prop-types
|
||||||
|
options={data[index].options}
|
||||||
|
// eslint-disable-next-line react/prop-types
|
||||||
onClick={data[index].onClick}
|
onClick={data[index].onClick}
|
||||||
style={style}
|
style={style}
|
||||||
/>
|
/>
|
||||||
@ -146,6 +148,25 @@ class NewContextMenu extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
position(event) {
|
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) {
|
if (event) {
|
||||||
let left = event.pageX + 1;
|
let left = event.pageX + 1;
|
||||||
let top = event.pageY + 1;
|
let top = event.pageY + 1;
|
||||||
@ -343,6 +364,7 @@ class NewContextMenu extends React.Component {
|
|||||||
icon={item.icon}
|
icon={item.icon}
|
||||||
label={item.label}
|
label={item.label}
|
||||||
isSeparator={item.isSeparator}
|
isSeparator={item.isSeparator}
|
||||||
|
options={item.options}
|
||||||
onClick={item.onClick}
|
onClick={item.onClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -356,10 +378,11 @@ class NewContextMenu extends React.Component {
|
|||||||
const className = classNames("p-contextmenu", this.props.className);
|
const className = classNames("p-contextmenu", this.props.className);
|
||||||
|
|
||||||
const items = this.renderContextMenuItems();
|
const items = this.renderContextMenuItems();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{this.props.withBackdrop && (
|
||||||
<Backdrop visible={this.state.visible} withBackground={true} />
|
<Backdrop visible={this.state.visible} withBackground={true} />
|
||||||
|
)}
|
||||||
<StyledContextMenu changeView={this.state.changeView}>
|
<StyledContextMenu changeView={this.state.changeView}>
|
||||||
<CSSTransition
|
<CSSTransition
|
||||||
nodeRef={this.menuRef}
|
nodeRef={this.menuRef}
|
||||||
@ -406,16 +429,20 @@ class NewContextMenu extends React.Component {
|
|||||||
NewContextMenu.propTypes = {
|
NewContextMenu.propTypes = {
|
||||||
/** Unique identifier of the element */
|
/** Unique identifier of the element */
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
/** An array of menuitems */
|
/** An array of objects */
|
||||||
model: PropTypes.array,
|
model: PropTypes.array,
|
||||||
/** An object of header */
|
/** An object of header with icon and label */
|
||||||
header: PropTypes.object,
|
header: PropTypes.object,
|
||||||
|
/** Position of context menu */
|
||||||
|
position: PropTypes.object,
|
||||||
/** Inline style of the component */
|
/** Inline style of the component */
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
/** Style class of the component */
|
/** Style class of the component */
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
/** Attaches the menu to document instead of a particular item */
|
/** Attaches the menu to document instead of a particular item */
|
||||||
global: PropTypes.bool,
|
global: PropTypes.bool,
|
||||||
|
/** Tell when context menu was render with backdrop */
|
||||||
|
withBackdrop: PropTypes.bool,
|
||||||
/** Base zIndex value to use in layering */
|
/** Base zIndex value to use in layering */
|
||||||
autoZIndex: PropTypes.bool,
|
autoZIndex: PropTypes.bool,
|
||||||
/** Whether to automatically manage layering */
|
/** Whether to automatically manage layering */
|
||||||
@ -431,6 +458,8 @@ NewContextMenu.propTypes = {
|
|||||||
NewContextMenu.defaultProps = {
|
NewContextMenu.defaultProps = {
|
||||||
id: null,
|
id: null,
|
||||||
model: null,
|
model: null,
|
||||||
|
position: null,
|
||||||
|
header: null,
|
||||||
style: null,
|
style: null,
|
||||||
className: null,
|
className: null,
|
||||||
global: false,
|
global: false,
|
||||||
@ -439,6 +468,7 @@ NewContextMenu.defaultProps = {
|
|||||||
appendTo: null,
|
appendTo: null,
|
||||||
onShow: null,
|
onShow: null,
|
||||||
onHide: null,
|
onHide: null,
|
||||||
|
withBackdrop: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NewContextMenu;
|
export default NewContextMenu;
|
||||||
|
@ -110,6 +110,20 @@ const Template = (args) => {
|
|||||||
icon: "/static/images/catalog.shared.react.svg",
|
icon: "/static/images/catalog.shared.react.svg",
|
||||||
key: "sharing-settings10",
|
key: "sharing-settings10",
|
||||||
label: "Sharing settings",
|
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"),
|
onClick: () => console.log("item 3 clicked"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user