init
This commit is contained in:
27
platform/ui/src/components/AllInOneMenu/BackItem.tsx
Normal file
27
platform/ui/src/components/AllInOneMenu/BackItem.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Icon } from '@ohif/ui';
|
||||
import DividerItem from './DividerItem';
|
||||
|
||||
type BackItemProps = {
|
||||
backLabel?: string;
|
||||
onBackClick: () => void;
|
||||
};
|
||||
|
||||
const BackItem = ({ backLabel, onBackClick }: BackItemProps) => {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="all-in-one-menu-item all-in-one-menu-item-effects"
|
||||
onClick={onBackClick}
|
||||
>
|
||||
<Icon name="content-prev"></Icon>
|
||||
|
||||
<div className="pl-2">{backLabel || 'Back to Display Options'}</div>
|
||||
</div>
|
||||
<DividerItem></DividerItem>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BackItem;
|
||||
11
platform/ui/src/components/AllInOneMenu/DividerItem.tsx
Normal file
11
platform/ui/src/components/AllInOneMenu/DividerItem.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
const DividerItem = () => {
|
||||
return (
|
||||
<div className="flex h-3.5 shrink-0 items-center px-2">
|
||||
<div className="bg-primary-dark h-[2px] w-full"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DividerItem;
|
||||
13
platform/ui/src/components/AllInOneMenu/HeaderItem.tsx
Normal file
13
platform/ui/src/components/AllInOneMenu/HeaderItem.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
|
||||
type HeaderItemProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const HeaderItem = ({ children }: HeaderItemProps) => {
|
||||
return (
|
||||
<div className="text-aqua-pale mx-2 flex h-6 shrink-0 items-center text-[11px]">{children}</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeaderItem;
|
||||
82
platform/ui/src/components/AllInOneMenu/IconMenu.tsx
Normal file
82
platform/ui/src/components/AllInOneMenu/IconMenu.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import OutsideClickHandler from 'react-outside-click-handler';
|
||||
import { MenuProps } from './Menu';
|
||||
import getIcon from '../Icon/getIcon';
|
||||
import classNames from 'classnames';
|
||||
import { AllInOneMenu } from '..';
|
||||
export interface IconMenuProps extends MenuProps {
|
||||
icon: string;
|
||||
iconClassName?: string;
|
||||
horizontalDirection?: AllInOneMenu.HorizontalDirection;
|
||||
verticalDirection?: AllInOneMenu.VerticalDirection;
|
||||
menuKey?: number | string;
|
||||
}
|
||||
|
||||
/**
|
||||
* An IconMenu allows for a div wrapped icon to be clicked to show and hide
|
||||
* an AllInOneMenu.Menu. Based on the direction(s) specified, the menu is
|
||||
* positioned relative to the icon.
|
||||
*
|
||||
* HorizontalDirection.LeftToRight - the left edges of the icon and menu are aligned
|
||||
* HorizontalDirection.RightRoLeft - the right edges of the icon and menu are aligned
|
||||
* VerticalDirection.TopToBottom - the top edge of the menu appears directly below the bottom edge of the icon
|
||||
* VerticalDirection.BottomToTop - the bottom edge of the menu appears directly above the top edge of the icon
|
||||
*
|
||||
* For example, if an IconMenu were situated in the bottom-left corner of a container,
|
||||
* it would be best to use BottomToTop and LeftToRight directions for it.
|
||||
*/
|
||||
export default function IconMenu({
|
||||
icon,
|
||||
iconClassName,
|
||||
horizontalDirection,
|
||||
verticalDirection,
|
||||
children,
|
||||
backLabel,
|
||||
menuClassName,
|
||||
menuStyle,
|
||||
onVisibilityChange,
|
||||
menuKey,
|
||||
}: IconMenuProps) {
|
||||
const [isMenuVisible, setIsMenuVisible] = useState(false);
|
||||
|
||||
const toggleMenuVisibility = useCallback(() => setIsMenuVisible(isVisible => !isVisible), []);
|
||||
|
||||
return (
|
||||
<OutsideClickHandler
|
||||
onOutsideClick={toggleMenuVisibility}
|
||||
disabled={!isMenuVisible}
|
||||
>
|
||||
<div className="relative">
|
||||
<div
|
||||
className={iconClassName}
|
||||
onClick={toggleMenuVisibility}
|
||||
>
|
||||
{getIcon(icon)}
|
||||
</div>
|
||||
<AllInOneMenu.Menu
|
||||
key={menuKey}
|
||||
isVisible={isMenuVisible}
|
||||
backLabel={backLabel}
|
||||
menuClassName={classNames(
|
||||
menuClassName,
|
||||
'absolute',
|
||||
verticalDirection === AllInOneMenu.VerticalDirection.TopToBottom
|
||||
? 'top-[100%]'
|
||||
: 'bottom-[100%]',
|
||||
horizontalDirection === AllInOneMenu.HorizontalDirection.LeftToRight
|
||||
? 'left-0'
|
||||
: 'right-0'
|
||||
)}
|
||||
menuStyle={menuStyle}
|
||||
onVisibilityChange={isVis => {
|
||||
setIsMenuVisible(isVis);
|
||||
onVisibilityChange?.(isVis);
|
||||
}}
|
||||
horizontalDirection={horizontalDirection}
|
||||
>
|
||||
{children}
|
||||
</AllInOneMenu.Menu>
|
||||
</div>
|
||||
</OutsideClickHandler>
|
||||
);
|
||||
}
|
||||
45
platform/ui/src/components/AllInOneMenu/Item.tsx
Normal file
45
platform/ui/src/components/AllInOneMenu/Item.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import React, { ReactNode, useCallback, useContext } from 'react';
|
||||
import { MenuContext } from './Menu';
|
||||
|
||||
type ItemProps = {
|
||||
label: string;
|
||||
secondaryLabel?: string;
|
||||
icon?: ReactNode;
|
||||
onClick?: () => void;
|
||||
onMouseEnter?: () => void;
|
||||
onMouseLeave?: () => void;
|
||||
rightIcon?: ReactNode;
|
||||
};
|
||||
|
||||
const Item = ({
|
||||
label,
|
||||
secondaryLabel,
|
||||
icon,
|
||||
rightIcon,
|
||||
onClick,
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
}: ItemProps) => {
|
||||
const { hideMenu } = useContext(MenuContext);
|
||||
|
||||
const onClickHandler = useCallback(() => {
|
||||
hideMenu();
|
||||
onClick?.();
|
||||
}, [hideMenu, onClick]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="all-in-one-menu-item all-in-one-menu-item-effects"
|
||||
onClick={onClickHandler}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
{icon && <div className="pr-2">{icon}</div>}
|
||||
<span>{label}</span>
|
||||
{secondaryLabel != null && <span className="text-aqua-pale ml-[1ch]">{secondaryLabel}</span>}
|
||||
{rightIcon && <div className="ml-auto">{rightIcon}</div>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Item;
|
||||
29
platform/ui/src/components/AllInOneMenu/ItemPanel.tsx
Normal file
29
platform/ui/src/components/AllInOneMenu/ItemPanel.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React, { ReactNode, useContext, useEffect } from 'react';
|
||||
import { MenuContext } from './Menu';
|
||||
|
||||
type ItemPanelProps = {
|
||||
label?: string;
|
||||
index?: number;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const ItemPanel = ({ label, index = 0, children }: ItemPanelProps) => {
|
||||
const { addItemPanel, activePanelIndex } = useContext(MenuContext);
|
||||
|
||||
useEffect(() => {
|
||||
addItemPanel(index, label);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
activePanelIndex === index && (
|
||||
<div
|
||||
style={{ scrollbarGutter: 'auto' }}
|
||||
className="ohif-scrollbar flex flex-col overflow-auto"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default ItemPanel;
|
||||
188
platform/ui/src/components/AllInOneMenu/Menu.tsx
Normal file
188
platform/ui/src/components/AllInOneMenu/Menu.tsx
Normal file
@@ -0,0 +1,188 @@
|
||||
import React, { createContext, ReactNode, useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import './allInOneMenu.css';
|
||||
import DividerItem from './DividerItem';
|
||||
import PanelSelector from './PanelSelector';
|
||||
import classNames from 'classnames';
|
||||
import BackItem from './BackItem';
|
||||
|
||||
/**
|
||||
* The vertical direction that the menu will be opened/used with.
|
||||
*
|
||||
* A TopToBottom menu would be used for cases where the menu is opened "near"
|
||||
* the top edge of its container. Likewise a BottomToTop menu would be used
|
||||
* for cases where the menu is opened "near" the bottom edge of its container.
|
||||
*
|
||||
* See IconMenu for more information.
|
||||
*/
|
||||
export enum VerticalDirection {
|
||||
TopToBottom,
|
||||
BottomToTop,
|
||||
}
|
||||
|
||||
/**
|
||||
* The horizontal direction that the menu is opened/used with.
|
||||
* This direction dictates the general direction sub-menus and
|
||||
* back-to-menus are opened with. For example, a RightToLeft menu
|
||||
* will have sub-menu items indicated with a left pointing chevron
|
||||
* and aligned with the left edge of the menu. Similarly back-to items of a
|
||||
* RightToLeft menu are indicated with a right pointing chevron and
|
||||
* aligned with the right edge of the menu.
|
||||
*
|
||||
* It is also worth noting that a LeftToRight menu would be used for
|
||||
* cases where a menu is opened "near" the left edge of its container.
|
||||
* Likewise, a RightToLeft menu would be used for cases where a menu is opened
|
||||
* "near" the right edge of its container.
|
||||
*
|
||||
* See IconMenu for more information.
|
||||
*/
|
||||
export enum HorizontalDirection {
|
||||
LeftToRight,
|
||||
RightToLeft,
|
||||
}
|
||||
|
||||
export interface MenuProps {
|
||||
menuStyle?: unknown;
|
||||
menuClassName?: string;
|
||||
isVisible?: boolean;
|
||||
preventHideMenu?: boolean;
|
||||
backLabel?: string;
|
||||
headerComponent?: ReactNode;
|
||||
showHeaderDivider?: boolean;
|
||||
activePanelIndex?: number;
|
||||
onVisibilityChange?: (isVisible: boolean) => void;
|
||||
horizontalDirection?: HorizontalDirection;
|
||||
children: ReactNode;
|
||||
}
|
||||
type MenuContextProps = {
|
||||
showSubMenu: (subMenuProps: MenuProps) => void;
|
||||
hideMenu: () => void;
|
||||
addItemPanel: (index: number, label: string) => void;
|
||||
horizontalDirection: HorizontalDirection;
|
||||
activePanelIndex: number;
|
||||
};
|
||||
|
||||
type MenuPathState = {
|
||||
props: MenuProps;
|
||||
activePanelIndex: number;
|
||||
};
|
||||
|
||||
export const MenuContext = createContext<MenuContextProps>(null);
|
||||
|
||||
const Menu = (props: MenuProps) => {
|
||||
const {
|
||||
isVisible,
|
||||
onVisibilityChange,
|
||||
activePanelIndex,
|
||||
preventHideMenu,
|
||||
menuClassName,
|
||||
menuStyle,
|
||||
horizontalDirection = HorizontalDirection.LeftToRight,
|
||||
} = props;
|
||||
|
||||
const [isMenuVisible, setIsMenuVisible] = useState(isVisible);
|
||||
|
||||
// The menuPath is an array consisting of this top Menu and every SubMenu
|
||||
// that has been traversed/opened by the user with the last item in the array
|
||||
// being the current (sub)menu that is currently visible. This allows for the previously
|
||||
// viewed menus to be returned to via the Back button at the top of the menu.
|
||||
const [menuPath, setMenuPath] = useState<Array<MenuPathState>>([
|
||||
{ props, activePanelIndex: activePanelIndex || 0 },
|
||||
]);
|
||||
const [itemPanelLabels, setItemPanelLabels] = useState<Array<string>>([]);
|
||||
|
||||
const hideMenu = useCallback(() => {
|
||||
if (preventHideMenu) {
|
||||
return;
|
||||
}
|
||||
setMenuPath(path => [path[0]]);
|
||||
setItemPanelLabels([]);
|
||||
setIsMenuVisible(false);
|
||||
onVisibilityChange?.(false);
|
||||
}, [preventHideMenu, onVisibilityChange]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isVisible) {
|
||||
setIsMenuVisible(isVisible);
|
||||
onVisibilityChange?.(isVisible);
|
||||
} else {
|
||||
hideMenu();
|
||||
}
|
||||
}, [hideMenu, isVisible, onVisibilityChange]);
|
||||
|
||||
const showSubMenu = useCallback((subMenuProps: MenuProps) => {
|
||||
setMenuPath(path => {
|
||||
return [
|
||||
...path,
|
||||
{ props: subMenuProps, activePanelIndex: subMenuProps.activePanelIndex || 0 },
|
||||
];
|
||||
});
|
||||
setItemPanelLabels([]);
|
||||
}, []);
|
||||
|
||||
const addItemPanel = useCallback((index, label) => {
|
||||
setItemPanelLabels(labels => {
|
||||
return [...labels.slice(0, index), label, ...labels.slice(index + 1, labels.length)];
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onActivePanelIndexChange = useCallback(index => {
|
||||
setMenuPath(path => {
|
||||
return [
|
||||
...path.slice(0, path.length - 1),
|
||||
{ ...path[path.length - 1], activePanelIndex: index },
|
||||
];
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onBackClick = useCallback(() => {
|
||||
setMenuPath(path => [...path.slice(0, path.length - 1)]);
|
||||
setItemPanelLabels([]);
|
||||
}, []);
|
||||
|
||||
const { props: currentMenuProps, activePanelIndex: currentMenuActivePanelIndex } =
|
||||
menuPath[menuPath.length - 1];
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuContext.Provider
|
||||
value={{
|
||||
showSubMenu,
|
||||
hideMenu,
|
||||
addItemPanel,
|
||||
activePanelIndex: currentMenuActivePanelIndex,
|
||||
horizontalDirection,
|
||||
}}
|
||||
>
|
||||
{isMenuVisible && (
|
||||
<div
|
||||
className={classNames(
|
||||
'bg-secondary-dark flex select-none flex-col rounded px-1 py-1.5 text-white opacity-90',
|
||||
menuClassName
|
||||
)}
|
||||
style={menuStyle}
|
||||
>
|
||||
{menuPath.length > 1 && (
|
||||
<BackItem
|
||||
backLabel={menuPath[menuPath.length - 2].props.backLabel}
|
||||
onBackClick={onBackClick}
|
||||
/>
|
||||
)}
|
||||
{itemPanelLabels.length > 1 && (
|
||||
<PanelSelector
|
||||
panelLabels={itemPanelLabels}
|
||||
activeIndex={currentMenuActivePanelIndex}
|
||||
onActiveIndexChange={onActivePanelIndexChange}
|
||||
></PanelSelector>
|
||||
)}
|
||||
{currentMenuProps.headerComponent}
|
||||
{currentMenuProps.showHeaderDivider && <DividerItem />}
|
||||
{currentMenuProps.children}
|
||||
</div>
|
||||
)}
|
||||
</MenuContext.Provider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Menu;
|
||||
31
platform/ui/src/components/AllInOneMenu/PanelSelector.tsx
Normal file
31
platform/ui/src/components/AllInOneMenu/PanelSelector.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import { ButtonGroup } from '../../components';
|
||||
|
||||
type PanelSelectorProps = {
|
||||
panelLabels: Array<ReactNode>;
|
||||
onActiveIndexChange: (index: number) => void;
|
||||
activeIndex: number;
|
||||
};
|
||||
|
||||
const PanelSelector = ({ panelLabels, onActiveIndexChange, activeIndex }: PanelSelectorProps) => {
|
||||
const getButtons = () => {
|
||||
return panelLabels.map((panelLabel, index) => {
|
||||
return {
|
||||
children: panelLabel,
|
||||
key: index,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-2 my-1 flex justify-center">
|
||||
<ButtonGroup
|
||||
buttons={getButtons()}
|
||||
onActiveIndexChange={onActiveIndexChange}
|
||||
defaultActiveIndex={activeIndex}
|
||||
></ButtonGroup>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PanelSelector;
|
||||
38
platform/ui/src/components/AllInOneMenu/SubMenu.tsx
Normal file
38
platform/ui/src/components/AllInOneMenu/SubMenu.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import React, { useCallback, useContext } from 'react';
|
||||
import { MenuContext, MenuProps } from './Menu';
|
||||
import Icon from '../Icon';
|
||||
|
||||
export interface SubMenuProps extends MenuProps {
|
||||
itemLabel: string;
|
||||
onClick?: () => void;
|
||||
itemIcon?: string;
|
||||
}
|
||||
|
||||
const SubMenu = (props: SubMenuProps) => {
|
||||
const { showSubMenu } = useContext(MenuContext);
|
||||
|
||||
const onClickHandler = useCallback(() => {
|
||||
showSubMenu(props);
|
||||
props.onClick?.();
|
||||
}, [showSubMenu, props]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="all-in-one-menu-item all-in-one-menu-item-effects flex items-center"
|
||||
onClick={onClickHandler}
|
||||
>
|
||||
{props.itemIcon && (
|
||||
<Icon
|
||||
name={props.itemIcon}
|
||||
width="25px"
|
||||
height="25px"
|
||||
className="mr-2"
|
||||
></Icon>
|
||||
)}
|
||||
<div className="mr-auto">{props.itemLabel}</div>
|
||||
<Icon name="content-next"></Icon>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubMenu;
|
||||
@@ -0,0 +1,129 @@
|
||||
import { DividerItem, HeaderItem, Item, ItemPanel, Menu, SubMenu } from '..';
|
||||
import InputRange from '../../InputRange/index.js';
|
||||
import SwitchButton from '../../SwitchButton/index.js';
|
||||
|
||||
import { ArgsTable, Story, Canvas, Meta } from '@storybook/addon-docs';
|
||||
|
||||
export const argTypes = {
|
||||
component: Menu,
|
||||
title: 'Components/AllInOneMenu',
|
||||
};
|
||||
|
||||
<Meta
|
||||
title="Components/AllInOneMenu"
|
||||
component={Menu}
|
||||
/>
|
||||
|
||||
export const AllInOneMenuTemplate = args => (
|
||||
<div className="w-80">
|
||||
<Menu {...args}>
|
||||
<ItemPanel>
|
||||
<Item
|
||||
label="Item 1"
|
||||
key="0"
|
||||
onClick={() => console.info('Item 1 clicked.')}
|
||||
></Item>
|
||||
<Item
|
||||
label="Item 2"
|
||||
secondaryLabel="Alt item 2"
|
||||
key="1"
|
||||
></Item>
|
||||
<div
|
||||
className="all-in-one-menu-item py-1"
|
||||
style={{ flexBasis: 'content' }}
|
||||
>
|
||||
<div>Arbitrary item component:</div>
|
||||
<InputRange
|
||||
minValue={1}
|
||||
maxValue={10}
|
||||
value={5}
|
||||
onChange={() => {}}
|
||||
></InputRange>
|
||||
</div>
|
||||
<DividerItem key="2"></DividerItem>
|
||||
<SubMenu
|
||||
key="3"
|
||||
backLabel="Back to Level 2"
|
||||
itemLabel="Item 3 opens a sub menu"
|
||||
onClick={() => console.info('Sub menu item clicked.')}
|
||||
showHeaderDivider={true}
|
||||
headerComponent={
|
||||
<div className="all-in-one-menu-item flex w-full justify-center">
|
||||
<SwitchButton label="Switch item in header" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<ItemPanel
|
||||
index={0}
|
||||
label="Panel A"
|
||||
>
|
||||
<Item label="Panel A item"></Item>
|
||||
</ItemPanel>
|
||||
<ItemPanel
|
||||
index={1}
|
||||
label="Panel B"
|
||||
>
|
||||
<Item label="Panel B item"></Item>
|
||||
<SubMenu
|
||||
itemLabel="Opens a sub, sub menu"
|
||||
headerComponent={<HeaderItem>Header for scrolling list of items</HeaderItem>}
|
||||
>
|
||||
<ItemPanel label="Sub sub Panel">
|
||||
<Item label="Sub sub menu item 1"></Item>
|
||||
<Item label="Sub sub menu item 2"></Item>
|
||||
<Item label="Sub sub menu item 3"></Item>
|
||||
<Item label="Sub sub menu item 4"></Item>
|
||||
<Item label="Sub sub menu item 5"></Item>
|
||||
<Item label="Sub sub menu item 6"></Item>
|
||||
</ItemPanel>
|
||||
</SubMenu>
|
||||
</ItemPanel>
|
||||
</SubMenu>
|
||||
</ItemPanel>
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
|
||||
<Heading
|
||||
title="AllInOneMenu"
|
||||
componentRelativePath="AllInOneMenu/AllInOneMenu.tsx"
|
||||
/>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Props](#props)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
## Overview
|
||||
|
||||
AllInOneMenu is a component that renders a menu with various menu items, sub-menus and
|
||||
sub-components. The particular feature of the AllInOneMenu is its ability to render a sub-menu by
|
||||
replacing the parent menu on screen. It also provides the ability to return to the parent menu with
|
||||
a back menu item from the sub-menu. Furthermore, each menu level can be split into item panes - that
|
||||
is several panes of menu items that are switched in and out of view like a tabbed pane.
|
||||
|
||||
<Canvas>
|
||||
<Story
|
||||
name="Overview"
|
||||
args={{
|
||||
className: 'max-h-[210px]',
|
||||
isVisible: true,
|
||||
preventHideMenu: true,
|
||||
backLabel: 'Back to Level 1',
|
||||
onVisibilityChange: (isVisible) => console.info(`The menu visibility: ${isVisible}`),
|
||||
}}
|
||||
>
|
||||
|
||||
{AllInOneMenuTemplate.bind({})}
|
||||
|
||||
</Story>
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
<ArgsTable of={Menu} />
|
||||
|
||||
## Usage
|
||||
|
||||
## Contribute
|
||||
|
||||
<Footer componentRelativePath="AllInOneMenu/__stories__/AllInOneMenu.stories.mdx" />
|
||||
11
platform/ui/src/components/AllInOneMenu/allInOneMenu.css
Normal file
11
platform/ui/src/components/AllInOneMenu/allInOneMenu.css
Normal file
@@ -0,0 +1,11 @@
|
||||
.all-in-one-menu-item {
|
||||
@apply h-8 px-2 text-[14px] w-full;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.all-in-one-menu-item-effects {
|
||||
@apply cursor-pointer hover:bg-primary-dark hover:rounded;
|
||||
}
|
||||
19
platform/ui/src/components/AllInOneMenu/index.tsx
Normal file
19
platform/ui/src/components/AllInOneMenu/index.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import Menu, { HorizontalDirection, VerticalDirection } from './Menu';
|
||||
import DividerItem from './DividerItem';
|
||||
import HeaderItem from './HeaderItem';
|
||||
import IconMenu from './IconMenu';
|
||||
import Item from './Item';
|
||||
import ItemPanel from './ItemPanel';
|
||||
import SubMenu from './SubMenu';
|
||||
|
||||
export {
|
||||
Menu,
|
||||
DividerItem,
|
||||
HeaderItem,
|
||||
IconMenu,
|
||||
Item,
|
||||
ItemPanel,
|
||||
SubMenu,
|
||||
HorizontalDirection,
|
||||
VerticalDirection,
|
||||
};
|
||||
Reference in New Issue
Block a user