Update new UI for mobile
This commit is contained in:
@@ -64,7 +64,8 @@ export default class Menu extends React.Component {
|
||||
elementRect,
|
||||
this.props.position,
|
||||
undefined,
|
||||
this.props.testClassId
|
||||
this.props.testClassId,
|
||||
this.props.enableMobileMenu,
|
||||
);
|
||||
this.setState({ isMenuOpen: true }, () => this.open = true);
|
||||
this.open = true;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import MenusManager from '@components/menus/menus-manager.jsx';
|
||||
import MenuComponent from './menu-component.jsx';
|
||||
import MenusManager from '@components/menus/menus-manager';
|
||||
import MenuComponent from './menu-component';
|
||||
import OutsideClickHandler from 'react-outside-click-handler';
|
||||
import MobileMenu from './mobile-menu';
|
||||
|
||||
/*
|
||||
Where the menu will be displayed, this component should be in app.js (menus should be over all elements of the page)
|
||||
@@ -194,24 +195,45 @@ export default class MenusBodyLayer extends React.Component {
|
||||
marginLeft: item.position.marginLeft,
|
||||
}}
|
||||
>
|
||||
<MenuComponent
|
||||
withFrame
|
||||
menu={item.menu}
|
||||
openAt={item.openAt}
|
||||
level={item.level}
|
||||
animationClass={
|
||||
this.state.menus_manager.willClose || item.willClose
|
||||
? 'fade_out'
|
||||
: item.level === 0 || item.positionType
|
||||
? item.positionType === 'bottom'
|
||||
? 'skew_in_bottom_nobounce'
|
||||
: item.left
|
||||
? 'skew_in_left_nobounce'
|
||||
: 'skew_in_right_nobounce'
|
||||
: 'fade_in'
|
||||
}
|
||||
testClassId={item.menuTestClassId}
|
||||
/>
|
||||
{item.enableMobileMenu ? (
|
||||
<MobileMenu
|
||||
withFrame
|
||||
menu={item.menu}
|
||||
openAt={item.openAt}
|
||||
level={item.level}
|
||||
animationClass={
|
||||
this.state.menus_manager.willClose || item.willClose
|
||||
? 'fade_out'
|
||||
: item.level === 0 || item.positionType
|
||||
? item.positionType === 'bottom'
|
||||
? 'skew_in_bottom_nobounce'
|
||||
: item.left
|
||||
? 'skew_in_left_nobounce'
|
||||
: 'skew_in_right_nobounce'
|
||||
: 'fade_in'
|
||||
}
|
||||
testClassId={item.menuTestClassId}
|
||||
/>
|
||||
) : (
|
||||
<MenuComponent
|
||||
withFrame
|
||||
menu={item.menu}
|
||||
openAt={item.openAt}
|
||||
level={item.level}
|
||||
animationClass={
|
||||
this.state.menus_manager.willClose || item.willClose
|
||||
? 'fade_out'
|
||||
: item.level === 0 || item.positionType
|
||||
? item.positionType === 'bottom'
|
||||
? 'skew_in_bottom_nobounce'
|
||||
: item.left
|
||||
? 'skew_in_left_nobounce'
|
||||
: 'skew_in_right_nobounce'
|
||||
: 'fade_in'
|
||||
}
|
||||
testClassId={item.menuTestClassId}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</OutsideClickHandler>
|
||||
);
|
||||
|
||||
@@ -57,7 +57,7 @@ class MenusManager extends Observable {
|
||||
|
||||
this.notify();
|
||||
}
|
||||
async openMenu(menu, domRect, positionType, options, menuTestClassId) {
|
||||
async openMenu(menu, domRect, positionType, options, menuTestClassId, enableMobileMenu) {
|
||||
this.isOpen = 1;
|
||||
if(typeof menu === 'function') {
|
||||
menu = await menu();
|
||||
@@ -86,6 +86,7 @@ class MenusManager extends Observable {
|
||||
id: Number.unid(),
|
||||
allowClickOut: options.allowClickOut !== undefined ? options.allowClickOut : true,
|
||||
menuTestClassId,
|
||||
enableMobileMenu,
|
||||
});
|
||||
this.last_opened_id = Number.unid();
|
||||
this.notify();
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import Icon from '@components/icon/icon.jsx';
|
||||
import { Modal, ModalContent } from '@atoms/modal';
|
||||
import Emojione from 'components/emojione/emojione';
|
||||
import MenusManager from '@components/menus/menus-manager.jsx';
|
||||
import './menu.scss';
|
||||
|
||||
/*
|
||||
One menu
|
||||
*/
|
||||
export default class MobileMenu extends React.Component {
|
||||
constructor(props) {
|
||||
super();
|
||||
this.state = {
|
||||
menus_manager: MenusManager,
|
||||
};
|
||||
MenusManager.addListener(this);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
MenusManager.removeListener(this);
|
||||
}
|
||||
openSubMenu(dom_element, menu, level) {
|
||||
var elementRect = window.getBoundingClientRect(dom_element);
|
||||
elementRect.x = elementRect.x || elementRect.left;
|
||||
elementRect.y = elementRect.y || elementRect.top;
|
||||
MenusManager.openSubMenu(menu, elementRect, level);
|
||||
}
|
||||
closeSubMenu(level) {
|
||||
MenusManager.closeSubMenu(level);
|
||||
}
|
||||
hoverMenu(dom_element, item) {
|
||||
if (item.submenu && !item.submenu_replace) {
|
||||
this.last_hovered = item;
|
||||
this.openSubMenu(dom_element, item.submenu, this.props.level || 0);
|
||||
} else {
|
||||
this.closeSubMenu(this.props.level || 0);
|
||||
}
|
||||
}
|
||||
clickMenu(dom_element, item, evt) {
|
||||
if(Date.now() - this.props.openAt < 200 ){
|
||||
// When a menu is open and another one opens above it, you have to block the buttons for a while. Otherwise, the hovered option of the new menu will be clicked
|
||||
return;
|
||||
}
|
||||
if (item.submenu_replace) {
|
||||
this.state.menus_manager.openMenu(item.submenu, { x: evt.clientX, y: evt.clientY }, 'center');
|
||||
return;
|
||||
}
|
||||
if (item.onClick) {
|
||||
var res = item.onClick(evt);
|
||||
if (res !== false) {
|
||||
this.state.menus_manager.closeMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Modal
|
||||
open={this.state.menus_manager.isOpen === 1}
|
||||
closable={true}
|
||||
onClose={() => this.state.menus_manager.closeMenu()}
|
||||
className={`md:!max-w-sm testid:${this.props.testClassId}`}
|
||||
disableCountVisibleModals={true}
|
||||
>
|
||||
<ModalContent title="">
|
||||
<div
|
||||
ref={node => (this.original_menu = node)}
|
||||
className={
|
||||
'menu-list sm:py-0 ' + (this.props.withFrame ? 'text-black bg-white dark:bg-zinc-900 dark:text-white rounded-lg ' : '') + this.props.animationClass
|
||||
}>
|
||||
{(this.props.menu || [])
|
||||
.filter(item => item && !item.hide)
|
||||
.map((item, index) => {
|
||||
if (item.type == 'separator') {
|
||||
return <div key={'menu_' + index} className="menu-separator" />;
|
||||
} else if (item.type == 'title') {
|
||||
return (
|
||||
<div key={'menu_' + index} className={'menu-title ' + item.className}>
|
||||
{item.text}
|
||||
</div>
|
||||
);
|
||||
} else if (item.type == 'text') {
|
||||
return (
|
||||
<div
|
||||
key={'menu_' + index}
|
||||
ref={node => (item.ref = node)}
|
||||
className={'menu-text ' + item.className + ' testid:menu-item'}
|
||||
onMouseEnter={evt => {
|
||||
this.hoverMenu(item.ref, item);
|
||||
}}
|
||||
>
|
||||
{item.icon && (
|
||||
<div className="icon">
|
||||
{typeof item.icon === 'string' ? <Icon type={item.icon} /> : item.icon}
|
||||
</div>
|
||||
)}
|
||||
<div className={`text testid:menu-item-${item.testClassId}`}>{item.text}</div>
|
||||
</div>
|
||||
);
|
||||
} else if (item.type == 'react-element') {
|
||||
return (
|
||||
<div
|
||||
key={'menu_' + index}
|
||||
className={'menu-custom ' + item.className + ' testid:menu-item'}
|
||||
onClick={item.onClick}
|
||||
>
|
||||
{typeof item.reactElement == 'function'
|
||||
? item.reactElement(this.props.level)
|
||||
: item.reactElement}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div
|
||||
key={'menu_' + index}
|
||||
ref={node => (item.ref = node)}
|
||||
className={
|
||||
'menu ' +
|
||||
item.className +
|
||||
' ' +
|
||||
(this.state.menus_manager.max_level > this.props.level &&
|
||||
this.last_hovered == item
|
||||
? 'hovered '
|
||||
: '') +
|
||||
(item.selected ? 'selected ' : '') +
|
||||
' testid:menu-item'
|
||||
}
|
||||
onMouseEnter={evt => {
|
||||
this.hoverMenu(item.ref, item);
|
||||
}}
|
||||
onClick={evt => {
|
||||
this.clickMenu(item.ref, item, evt);
|
||||
}}
|
||||
>
|
||||
{item.icon && (
|
||||
<div className="icon">
|
||||
{typeof item.icon === 'string' ? <Icon type={item.icon} /> : item.icon}
|
||||
</div>
|
||||
)}
|
||||
{item.emoji && (
|
||||
<div className="icon">
|
||||
<Emojione type={item.emoji} />
|
||||
</div>
|
||||
)}
|
||||
<div className={`text testid:menu-item-${item.testClassId}`}>{item.text}</div>
|
||||
<div className="more">
|
||||
{item.rightIcon && <Icon type={item.rightIcon} />}
|
||||
{item.submenu && !item.submenu_replace && <Icon type="angle-right" />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user