diff --git a/frontend/src/components/v2/Menu/Menu.stories.tsx b/frontend/src/components/v2/Menu/Menu.stories.tsx new file mode 100644 index 000000000..1523426e8 --- /dev/null +++ b/frontend/src/components/v2/Menu/Menu.stories.tsx @@ -0,0 +1,107 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { faKey, faUser } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { Meta, StoryObj } from '@storybook/react'; + +import { Menu, MenuGroup, MenuItem } from './Menu'; + +const meta: Meta = { + title: 'Components/Menu', + component: Menu, + tags: ['v2'], + argTypes: {} +}; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + render: (args) => ( + + Secrets + Members + Integrations + + ), + args: {} +}; + +export const SelectedItem: Story = { + render: (args) => ( + + Secrets + Members + Integrations + + ), + args: {} +}; + +export const GroupedItem: Story = { + render: (args) => ( + + + Secrets + Members + + + Secrets + Members + + + ), + args: {} +}; + +export const DisabledItem: Story = { + render: (args) => ( + + + Secrets + Members + + + Secrets + Members + + + ), + args: {} +}; + +export const WithIcons: Story = { + render: (args) => ( + + + }> + Secrets + + }>Members + + + }>Secrets + }>Members + + + ), + args: {} +}; + +export const WithDescription: Story = { + render: (args) => ( + + } + description="Some random description" + > + Secrets + + } description="Some random description"> + Members + + + ), + args: {} +}; diff --git a/frontend/src/components/v2/Menu/Menu.tsx b/frontend/src/components/v2/Menu/Menu.tsx new file mode 100644 index 000000000..54bb08a46 --- /dev/null +++ b/frontend/src/components/v2/Menu/Menu.tsx @@ -0,0 +1,64 @@ +import { ComponentPropsWithRef, ElementType, ReactNode, Ref } from 'react'; +import { twMerge } from 'tailwind-merge'; + +export type MenuProps = { + children: ReactNode; + className?: string; +}; + +export const Menu = ({ children, className }: MenuProps): JSX.Element => { + return ; +}; + +export type MenuItemProps = { + // Kudos to https://itnext.io/react-polymorphic-components-with-typescript-f7ce72ea7af2 + as?: T; + children: ReactNode; + icon?: ReactNode; + description?: ReactNode; + isDisabled?: boolean; + isSelected?: boolean; + className?: string; + inputRef?: Ref; +}; + +export const MenuItem = ({ + children, + icon, + className, + isDisabled, + isSelected, + as: Item = 'button', + description, + // wrapping in forward ref with generic component causes the loss of ts definitions on props + inputRef +}: MenuItemProps & ComponentPropsWithRef): JSX.Element => ( +
  • + + {icon && {icon}} + {children} + + {description && {description}} +
  • +); + +MenuItem.displayName = 'MenuItem'; + +export type MenuGroupProps = { + children: ReactNode; + title: ReactNode; +}; + +export const MenuGroup = ({ children, title }: MenuGroupProps): JSX.Element => ( + <> +
  • {title}
  • + {children} + +); diff --git a/frontend/src/components/v2/Menu/index.tsx b/frontend/src/components/v2/Menu/index.tsx new file mode 100644 index 000000000..09fed20fb --- /dev/null +++ b/frontend/src/components/v2/Menu/index.tsx @@ -0,0 +1,2 @@ +export type { MenuGroupProps, MenuItemProps, MenuProps } from './Menu'; +export { Menu, MenuGroup, MenuItem } from './Menu'; diff --git a/frontend/src/components/v2/index.tsx b/frontend/src/components/v2/index.tsx index be30514a8..401a02e94 100644 --- a/frontend/src/components/v2/index.tsx +++ b/frontend/src/components/v2/index.tsx @@ -3,5 +3,6 @@ export * from './Card'; export * from './FormControl'; export * from './IconButton'; export * from './Input'; +export * from './Menu'; export * from './Modal'; export * from './Select';