Menu.tsx130 lines · main
1'use client'
2
3import React from 'react'
4
5import styleHandler from '../../lib/theme/styleHandler'
6import { cn } from '../../lib/utils/cn'
7import Typography from '../Typography'
8import { MenuContextProvider, useMenuContext } from './MenuContext'
9
10interface MenuProps {
11 children: React.ReactNode
12 className?: string
13 ulClassName?: string
14 style?: React.CSSProperties
15 type?: 'text' | 'pills' | 'border'
16}
17
18function Menu({ children, className, ulClassName, style, type = 'text' }: MenuProps) {
19 return (
20 <nav
21 role="menu"
22 aria-label="Sidebar"
23 aria-orientation="vertical"
24 aria-labelledby="options-menu"
25 className={className}
26 style={style}
27 >
28 <MenuContextProvider type={type}>
29 <ul className={ulClassName}>{children}</ul>
30 </MenuContextProvider>
31 </nav>
32 )
33}
34
35interface ItemProps {
36 children: React.ReactNode
37 icon?: React.ReactNode
38 active?: boolean
39 rounded?: boolean
40 onClick?: any
41 doNotCloseOverlay?: boolean
42 showActiveBar?: boolean
43 style?: React.CSSProperties
44}
45
46export function Item({ children, icon, active, onClick, style }: ItemProps) {
47 const __styles = styleHandler('menu')
48
49 const { type } = useMenuContext()
50
51 let classes = [__styles.item.base]
52
53 classes.push(__styles.item.variants[type].base)
54
55 if (active) {
56 classes.push(__styles.item.variants[type].active)
57 } else {
58 classes.push(__styles.item.variants[type].normal)
59 }
60
61 let contentClasses = [__styles.item.content.base]
62 if (active) {
63 contentClasses.push(__styles.item.content.active)
64 } else {
65 contentClasses.push(__styles.item.content.normal)
66 }
67
68 let iconClasses = [__styles.item.icon.base]
69 if (active) {
70 iconClasses.push(__styles.item.icon.active)
71 } else {
72 iconClasses.push(__styles.item.icon.normal)
73 }
74
75 return (
76 <li
77 role="menuitem"
78 className={cn('outline-hidden', classes)}
79 style={style}
80 onClick={onClick}
81 aria-current={active ? 'page' : undefined}
82 >
83 {icon && <div className={`${iconClasses.join(' ')} min-w-fit`}>{icon}</div>}
84 <span className={contentClasses.join(' ')}>{children}</span>
85 </li>
86 )
87}
88
89interface GroupProps {
90 children?: React.ReactNode
91 icon?: React.ReactNode
92 title: React.ReactNode
93}
94
95export function Group({ children, icon, title }: GroupProps) {
96 const __styles = styleHandler('menu')
97 const { type } = useMenuContext()
98 return (
99 <div className={[__styles.group.base, __styles.group.variants[type]].join(' ')}>
100 {icon && <span className={__styles.group.icon}>{icon}</span>}
101 <span className={__styles.group.content}>{title}</span>
102 {children}
103 </div>
104 )
105}
106
107interface MiscProps {
108 children: React.ReactNode
109}
110
111export function Misc({ children }: MiscProps) {
112 return (
113 <div
114 // className={MenuStyles['sbui-menu__misc']}
115 >
116 <Typography.Text>
117 <span
118 // className={MenuStyles['sbui-menu__content']}
119 >
120 {children}
121 </span>
122 </Typography.Text>
123 </div>
124 )
125}
126
127Menu.Item = Item
128Menu.Group = Group
129Menu.Misc = Misc
130export default Menu