/ libs / ui / src / components / menubar.rs
menubar.rs
  1  use dioxus::html::GlobalAttributesExtension;
  2  use dioxus::prelude::*;
  3  use dioxus_primitives::menubar::{
  4      Menubar as PrimitiveMenubar, MenubarContent as PrimitiveMenubarContent,
  5      MenubarItem as PrimitiveMenubarItem, MenubarMenu as PrimitiveMenubarMenu,
  6      MenubarTrigger as PrimitiveMenubarTrigger,
  7  };
  8  
  9  /// Menubar main container, styled with Tailwind
 10  #[derive(Props, Clone, PartialEq)]
 11  pub struct MenubarProps {
 12      #[props(default)]
 13      pub class: Option<String>,
 14      pub children: Element,
 15  }
 16  
 17  #[component]
 18  pub fn Menubar(props: MenubarProps) -> Element {
 19      let default_classes =
 20          "flex items-center gap-1 px-1 py-1 border border-border bg-background rounded-md shadow-sm";
 21      let class = if let Some(extra) = &props.class {
 22          format!("{} {}", extra, default_classes)
 23      } else {
 24          default_classes.to_string()
 25      };
 26  
 27      rsx! {
 28          PrimitiveMenubar {
 29              class: class,
 30              {props.children}
 31          }
 32      }
 33  }
 34  
 35  /// MenubarMenu: A single menu in the menubar, styled with Tailwind
 36  #[derive(Props, Clone, PartialEq)]
 37  pub struct MenubarMenuProps {
 38      #[props(default)]
 39      pub class: Option<String>,
 40      pub index: ReadSignal<usize>,
 41      pub children: Element,
 42  }
 43  
 44  #[component]
 45  pub fn MenubarMenu(props: MenubarMenuProps) -> Element {
 46      let default_classes = "relative group flex flex-col items-stretch";
 47      let class = if let Some(extra) = &props.class {
 48          format!("{} {}", extra, default_classes)
 49      } else {
 50          default_classes.to_string()
 51      };
 52  
 53      rsx! {
 54          PrimitiveMenubarMenu {
 55              class: class,
 56              index: props.index,
 57              {props.children}
 58          }
 59      }
 60  }
 61  
 62  /// MenubarTrigger: The button that opens a menu, styled with Tailwind
 63  #[derive(Props, Clone, PartialEq)]
 64  pub struct MenubarTriggerProps {
 65      #[props(default)]
 66      pub class: Option<String>,
 67      pub children: Element,
 68  }
 69  
 70  #[component]
 71  pub fn MenubarTrigger(props: MenubarTriggerProps) -> Element {
 72      let default_classes = "px-3 py-1.5 rounded-sm text-sm font-medium text-foreground hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring transition-colors";
 73      let class = if let Some(extra) = &props.class {
 74          format!("{} {}", extra, default_classes)
 75      } else {
 76          default_classes.to_string()
 77      };
 78  
 79      rsx! {
 80          PrimitiveMenubarTrigger {
 81              class: class,
 82              {props.children}
 83          }
 84      }
 85  }
 86  
 87  /// MenubarContent: The dropdown content for a menu, styled with Tailwind
 88  #[derive(Props, Clone, PartialEq)]
 89  pub struct MenubarContentProps {
 90      #[props(default)]
 91      pub class: Option<String>,
 92      pub children: Element,
 93  }
 94  
 95  #[component]
 96  pub fn MenubarContent(props: MenubarContentProps) -> Element {
 97      let default_classes = "hidden group-data-[state=open]:block absolute left-0 top-full mt-2 min-w-[10rem] bg-popover border border-border rounded-md shadow-lg z-50 p-1";
 98      let class = if let Some(extra) = &props.class {
 99          format!("{} {}", extra, default_classes)
100      } else {
101          default_classes.to_string()
102      };
103  
104      rsx! {
105          PrimitiveMenubarContent {
106              class: class,
107              {props.children}
108          }
109      }
110  }
111  
112  /// MenubarItem: An item in a menu, styled with Tailwind
113  #[derive(Props, Clone, PartialEq)]
114  pub struct MenubarItemProps {
115      /// The index of this item within the [`MenubarContent`]. This is used to define the focus order for keyboard navigation.
116      pub index: ReadSignal<usize>,
117      #[props(default)]
118      pub class: Option<String>,
119      pub value: String,
120      #[props(default)]
121      pub on_select: Callback<String>,
122      pub children: Element,
123  }
124  
125  #[component]
126  pub fn MenubarItem(props: MenubarItemProps) -> Element {
127      let default_classes = "menubar-item cursor-pointer select-none px-3 py-1.5 rounded-sm text-sm text-foreground hover:bg-accent focus:bg-accent focus:outline-none transition-colors";
128      let class = if let Some(extra) = &props.class {
129          format!("{} {}", extra, default_classes)
130      } else {
131          default_classes.to_string()
132      };
133  
134      rsx! {
135          PrimitiveMenubarItem {
136              index: props.index,
137              class: class,
138              value: props.value.clone(),
139              on_select: props.on_select,
140              {props.children}
141          }
142      }
143  }