woocraft 0.4.5

GPUI components lib for Woocraft design system.
Documentation
use std::rc::Rc;

use gpui::{Context, DismissEvent, ElementId, Entity, Focusable, Window};

use crate::{PopoverState, PopupMenu};

pub(crate) type MenuBuilderFn =
  dyn Fn(PopupMenu, &mut Window, &mut Context<PopupMenu>) -> PopupMenu;

#[derive(Default)]
struct PopupMenuHostState {
  menu: Option<Entity<PopupMenu>>,
}

pub(crate) fn render_popup_menu(
  state_id: ElementId, builder: Rc<MenuBuilderFn>, popover: Entity<PopoverState>,
  window: &mut Window, cx: &mut Context<PopoverState>,
) -> Entity<PopupMenu> {
  let menu_state = window.use_keyed_state(state_id, cx, |_, _| PopupMenuHostState::default());

  match menu_state.read(cx).menu.clone() {
    Some(menu) => menu,
    None => {
      let builder = builder.clone();
      let menu = PopupMenu::build(window, cx, move |menu, window, cx| {
        builder(menu, window, cx)
      });

      menu_state.update(cx, |state, _| {
        state.menu = Some(menu.clone());
      });

      menu.focus_handle(cx).focus(window);

      window
        .subscribe(&menu, cx, {
          let menu_state = menu_state.clone();
          move |_, _: &DismissEvent, window, cx| {
            popover.update(cx, |state, cx| {
              state.dismiss(window, cx);
            });
            menu_state.update(cx, |state, _| {
              state.menu = None;
            });
          }
        })
        .detach();

      menu
    }
  }
}