DEV;Add MenuItem new option - onClick

This commit is contained in:
Roman Jaroš 2022-07-24 20:45:03 +02:00
parent 4658595a62
commit e3b89dabac
7 changed files with 46 additions and 37 deletions

View file

@ -6,15 +6,17 @@ import ChevronDownIcon from '@treejs/components/Icons/ChevronDown';
import ChevronUpIcon from '@treejs/components/Icons/ChevronUp';
import { isNilOrEmpty } from '@treejs/utils';
import { IMenuItem } from '../types';
import { MenuItem } from '../types';
type IProps = {
isChild: boolean;
onClick: (href: string, external: boolean) => () => void;
} & IMenuItem;
item: MenuItem;
onClick: (menuItem: MenuItem) => void;
};
export const SidebarMenuItem = (props: IProps) => {
const { defaultOpen, href, onClick, isChild, label, external, subMenu } = props;
const { onClick, isChild, item } = props;
const { defaultOpen, href, label, subMenu } = item;
const [open, setOpen] = useState(defaultOpen);
@ -24,16 +26,16 @@ export const SidebarMenuItem = (props: IProps) => {
const handleOnClick = useCallback(() => {
if (!isNilOrEmpty(href)) {
onClick(href, external)();
onClick(item);
} else {
setOpen(!open);
}
}, [open, href, external]);
}, [open, item]);
const items = useMemo(() => {
if (open && !isNilOrEmpty(subMenu)) {
return subMenu.map((menuItem, i) => (
<SidebarMenuItem key={i} isChild={true} onClick={onClick} {...menuItem} />
return subMenu.map((subMenuItem, i) => (
<SidebarMenuItem key={i} isChild={true} item={subMenuItem} onClick={onClick} />
));
} else {
return null;

View file

@ -1,4 +1,5 @@
import React, { useCallback, useMemo, useState } from 'react';
import { isNil } from 'ramda';
import cx from 'classnames';
import { History } from 'history';
@ -9,7 +10,7 @@ import { isNilOrEmpty } from '@treejs/utils';
import Modals from '../../Modal/components/Modals';
import Toasters from '../../Toaster/components/Toasters';
import { IMenuItem } from '../types';
import { MenuItem } from '../types';
import SidebarMenuItem from './SidebarMenuItem';
import UserMenu from './UserMenu';
@ -27,9 +28,9 @@ type IProps = {
};
history: History;
menuItems?: {
navigation?: IMenuItem[];
sidebar?: IMenuItem[];
user?: IMenuItem[];
navigation?: MenuItem[];
sidebar?: MenuItem[];
user?: MenuItem[];
};
};
@ -61,11 +62,15 @@ const Skeleton: React.FC<IProps> = (props) => {
}, [sidebarOpened]);
const openLink = useCallback(
(link: string, external: boolean) => () => {
if (external) {
window.open(link, '_blank');
({ href, external, onClick }: MenuItem) => {
if (!isNil(onClick)) {
onClick();
} else {
history.push(link);
if (external) {
window.open(href, '_blank');
} else {
history.push(href);
}
}
setSidebarOpened(false);
},
@ -75,7 +80,7 @@ const Skeleton: React.FC<IProps> = (props) => {
const sidebarItems = useMemo(() => {
if (!isNilOrEmpty(menuItems.sidebar)) {
return menuItems.sidebar.map((menuItem, i) => (
<SidebarMenuItem key={i} isChild={false} onClick={openLink} {...menuItem} />
<SidebarMenuItem key={i} isChild={false} onClick={openLink} item={menuItem} />
));
} else {
return null;
@ -84,9 +89,10 @@ const Skeleton: React.FC<IProps> = (props) => {
const navigationItems = useMemo(() => {
if (!isNilOrEmpty(menuItems.navigation)) {
return menuItems.navigation.map(({ label, href, external }, i) => (
<div key={i} className="navigation-item" onClick={openLink(href, external)}>
{label}
return menuItems.navigation.map((menuItem, i) => (
// eslint-disable-next-line react/jsx-no-bind
<div key={i} className="navigation-item" onClick={() => openLink(menuItem)}>
{menuItem.label}
</div>
));
} else {

View file

@ -2,24 +2,22 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { isNilOrEmpty } from '@treejs/utils';
import { IMenuItem } from '../types';
import { MenuItem } from '../types';
type IProps = {
children: React.ReactElement;
items: IMenuItem[];
onClick: (href: string, external: boolean) => () => void;
items: MenuItem[];
onClick: (menuItem: MenuItem) => void;
};
export const UserMenu = (props: IProps) => {
const { items, onClick, children } = props;
export const UserMenu: React.FC<IProps> = ({ items, onClick, children }) => {
const divRef = useRef<HTMLDivElement>();
const [open, setOpen] = useState(false);
const handleClick = useCallback(
(href: string, external: boolean) => () => {
onClick(href, external)();
(item: MenuItem) => () => {
onClick(item);
setOpen(false);
},
[onClick]
@ -37,9 +35,9 @@ export const UserMenu = (props: IProps) => {
const userItems = useMemo(() => {
if (!isNilOrEmpty(items)) {
return items.map(({ label, href, external }, i) => (
<div key={i} className="user-item" onClick={handleClick(href, external)}>
{label}
return items.map((menuItem, i) => (
<div key={i} className="user-item" onClick={handleClick(menuItem)}>
{menuItem.label}
</div>
));
} else {

View file

@ -1,7 +1,8 @@
export interface IMenuItem {
export type MenuItem = {
defaultOpen?: boolean;
external?: boolean;
href?: string;
label: string;
subMenu?: IMenuItem[];
}
onClick?: () => void;
subMenu?: MenuItem[];
};

View file

@ -41,10 +41,11 @@ export const Template = (args) => (
{ label: 'Menu External', href: 'https://treejs.romanjaros.dev', external: true },
],
sidebar: [{ label: 'Menu 1' }, { label: 'Menu 2' }],
user: [{ label: 'Menu 1' }, { label: 'Menu 2', href: '/r3' }],
user: [{ label: 'Menu 1', href: '/ru1' }, { label: 'Menu 2', href: '/ru2' }],
},
enabledMenu: {
user: true,
navigation: true,
sidebar: true,
},
}}

View file

@ -7,7 +7,8 @@ const Router = () => (
<Route path="/" element={<div>Main</div>} />
<Route path="/r1" element={<div>Conten 1</div>} />
<Route path="/r2" element={<div>Conten 2</div>} />
<Route path="/r3" element={<div>User content 2</div>} />
<Route path="/ru1" element={<div>User content 1</div>} />
<Route path="/ru2" element={<div>User content 2</div>} />
</Routes>
);

View file

@ -24,6 +24,6 @@ const composeSetup = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
const store = createStore(mainReducer, composeSetup(applyMiddleware(thunk)));
// eslint-disable-next-line react/display-name
const StoreProvider: React.FC = ({ children }) => <Provider store={store}>{children}</Provider>;
const StoreProvider: React.FC = ({ children }: any) => <Provider store={store}>{children}</Provider>;
export default StoreProvider;