feat: add Menu component with sub-components
This commit is contained in:
107
src/components/ui/Menu.tsx
Normal file
107
src/components/ui/Menu.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { useRender } from '@base-ui/react/use-render'
|
||||
import { cx } from '@styled-system/css'
|
||||
import { type MenuVariantProps, menu } from '@styled-system/recipes/menu'
|
||||
import type { FC, ReactNode } from 'react'
|
||||
import type { MergeOmitting } from '@/types/helpers'
|
||||
|
||||
export type MenuProps = MergeOmitting<
|
||||
useRender.ComponentProps<'div'>,
|
||||
MenuVariantProps
|
||||
>
|
||||
|
||||
const Menu: FC<MenuProps> = ({ render, className, ...props }) => {
|
||||
const [menuProps, allOther] = menu.splitVariantProps(props)
|
||||
return useRender({
|
||||
defaultTagName: 'div',
|
||||
render,
|
||||
props: { className: cx(menu(menuProps).container, className), ...allOther }
|
||||
})
|
||||
}
|
||||
|
||||
export default Menu
|
||||
|
||||
export type MenuItemProps = MergeOmitting<
|
||||
useRender.ComponentProps<'button'>,
|
||||
MenuVariantProps
|
||||
>
|
||||
|
||||
export const MenuItem: FC<MenuItemProps> = ({
|
||||
render,
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const [menuProps, allOther] = menu.splitVariantProps(props)
|
||||
return useRender({
|
||||
defaultTagName: 'button',
|
||||
render,
|
||||
props: { className: cx(menu(menuProps).item, className), ...allOther }
|
||||
})
|
||||
}
|
||||
|
||||
export type MenuLabelProps = MergeOmitting<
|
||||
useRender.ComponentProps<'span'>,
|
||||
MenuVariantProps
|
||||
>
|
||||
|
||||
export const MenuLabel: FC<MenuLabelProps> = ({
|
||||
render,
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const [menuProps, allOther] = menu.splitVariantProps(props)
|
||||
|
||||
return useRender({
|
||||
defaultTagName: 'span',
|
||||
render,
|
||||
props: { className: cx(menu(menuProps).label, className), ...allOther }
|
||||
})
|
||||
}
|
||||
|
||||
export type MenuGroupProps = MergeOmitting<
|
||||
useRender.ComponentProps<'div'>,
|
||||
MenuVariantProps & { label: ReactNode }
|
||||
>
|
||||
|
||||
export const MenuGroup: FC<MenuGroupProps> = ({
|
||||
render,
|
||||
children,
|
||||
className,
|
||||
label,
|
||||
...props
|
||||
}) => {
|
||||
const [menuProps, allOther] = menu.splitVariantProps(props)
|
||||
return useRender({
|
||||
defaultTagName: 'div',
|
||||
render,
|
||||
|
||||
props: {
|
||||
className: cx(menu(menuProps).group, className),
|
||||
children: (
|
||||
<>
|
||||
<span className={cx(menu(menuProps).label)}>{label}</span>
|
||||
{children}
|
||||
</>
|
||||
),
|
||||
...allOther
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export type MenuSeparatorProps = MergeOmitting<
|
||||
Omit<useRender.ComponentProps<'div'>, 'children'>,
|
||||
MenuVariantProps
|
||||
>
|
||||
|
||||
export const MenuSeparator: FC<MenuSeparatorProps> = ({
|
||||
render,
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const [menuProps, allOther] = menu.splitVariantProps(props)
|
||||
|
||||
return useRender({
|
||||
defaultTagName: 'div',
|
||||
render,
|
||||
props: { className: cx(menu(menuProps).separator, className), ...allOther }
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user