menu.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. """Menu components."""
  2. from __future__ import annotations
  3. from typing import Any, List, Optional, Union
  4. from reflex.components.component import Component
  5. from reflex.components.libs.chakra import ChakraComponent
  6. from reflex.vars import Var
  7. class Menu(ChakraComponent):
  8. """The wrapper component provides context, state, and focus management."""
  9. tag = "Menu"
  10. # The padding required to prevent the arrow from reaching the very edge of the popper.
  11. arrow_padding: Var[int]
  12. # If true, the first enabled menu item will receive focus and be selected when the menu opens.
  13. auto_select: Var[bool]
  14. # The boundary area for the popper. Used within the preventOverflow modifier
  15. boundary: Var[str]
  16. # If true, the menu will close when you click outside the menu list
  17. close_on_blur: Var[bool]
  18. # If true, the menu will close when a menu item is clicked
  19. close_on_select: Var[bool]
  20. # If by default the menu is open.
  21. default_is_open: Var[bool]
  22. # If rtl, popper placement positions will be flipped i.e. 'top-right' will become 'top-left' and vice-verse ("ltr" | "rtl")
  23. direction: Var[str]
  24. # If true, the popper will change its placement and flip when it's about to overflow its boundary area.
  25. flip: Var[bool]
  26. # The distance or margin between the reference and popper. It is used internally to create an offset modifier. NB: If you define offset prop, it'll override the gutter.
  27. gutter: Var[int]
  28. # Performance 🚀: If true, the MenuItem rendering will be deferred until the menu is open.
  29. is_lazy: Var[bool]
  30. # Performance 🚀: The lazy behavior of menu's content when not visible. Only works when `isLazy={true}` - "unmount": The menu's content is always unmounted when not open. - "keepMounted": The menu's content initially unmounted, but stays mounted when menu is open.
  31. lazy_behavior: Var[str]
  32. # Determines if the menu is open or not.
  33. is_open: Var[bool]
  34. # If true, the popper will match the width of the reference at all times. It's useful for autocomplete, `date-picker` and select patterns.
  35. match_width: Var[bool]
  36. # The placement of the popper relative to its reference.
  37. placement: Var[str]
  38. # If true, will prevent the popper from being cut off and ensure it's visible within the boundary area.
  39. prevent_overflow: Var[bool]
  40. # The CSS positioning strategy to use. ("fixed" | "absolute")
  41. strategy: Var[str]
  42. def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
  43. """Get the event triggers for the component.
  44. Returns:
  45. The event triggers.
  46. """
  47. return {
  48. **super().get_event_triggers(),
  49. "on_close": lambda: [],
  50. "on_open": lambda: [],
  51. }
  52. @classmethod
  53. def create(
  54. cls,
  55. *children,
  56. button: Optional[Component] = None,
  57. items: Optional[List] = None,
  58. **props,
  59. ) -> Component:
  60. """Create a menu component.
  61. Args:
  62. *children: The children of the component.
  63. button: the button that open the menu.
  64. items (list): The items of the menu.
  65. **props: The properties of the component.
  66. Returns:
  67. The menu component.
  68. """
  69. if len(children) == 0:
  70. children = []
  71. if button:
  72. children.append(MenuButton.create(button))
  73. if not items:
  74. items = []
  75. children.append(MenuList.create(*items))
  76. return super().create(*children, **props)
  77. class MenuButton(ChakraComponent):
  78. """The trigger for the menu list. Must be a direct child of Menu."""
  79. tag = "MenuButton"
  80. # The variant of the menu button.
  81. variant: Var[str]
  82. # Components that are not allowed as children.
  83. invalid_children: List[str] = ["Button", "MenuButton"]
  84. # The tag to use for the menu button.
  85. as_: Var[str]
  86. class MenuList(ChakraComponent):
  87. """The wrapper for the menu items. Must be a direct child of Menu."""
  88. tag = "MenuList"
  89. @classmethod
  90. def create(cls, *children, **props) -> ChakraComponent:
  91. """Create a MenuList component, and automatically wrap in MenuItem if not already one.
  92. Args:
  93. *children: The children of the component.
  94. **props: The properties of the component.
  95. Returns:
  96. The MenuList component.
  97. """
  98. if len(children) != 0:
  99. children = [
  100. child if isinstance(child, MenuItem) else MenuItem.create(child)
  101. for child in children
  102. ]
  103. return super().create(*children, **props)
  104. class MenuItem(ChakraComponent):
  105. """The trigger that handles menu selection. Must be a direct child of a MenuList."""
  106. tag = "MenuItem"
  107. # Overrides the parent menu's closeOnSelect prop.
  108. close_on_select: Var[bool]
  109. # Right-aligned label text content, useful for displaying hotkeys.
  110. command: Var[str]
  111. # The spacing between the command and menu item's label.
  112. command_spacing: Var[int]
  113. # If true, the menuitem will be disabled.
  114. is_disabled: Var[bool]
  115. # If true and the menuitem is disabled, it'll remain keyboard-focusable
  116. is_focusable: Var[bool]
  117. class MenuItemOption(ChakraComponent):
  118. """The checkable menu item, to be used with MenuOptionGroup."""
  119. tag = "MenuItemOption"
  120. # Overrides the parent menu's closeOnSelect prop.
  121. close_on_select: Var[bool]
  122. # Right-aligned label text content, useful for displaying hotkeys.
  123. command: Var[str]
  124. # The spacing between the command and menu item's label.
  125. command_spacing: Var[int]
  126. # Determines if menu item is checked.
  127. is_checked: Var[bool]
  128. # If true, the menuitem will be disabled.
  129. is_disabled: Var[bool]
  130. # If true and the menuitem is disabled, it'll remain keyboard-focusable
  131. is_focusable: Var[bool]
  132. # "checkbox" | "radio"
  133. type_: Var[str]
  134. # Value of the menu item.
  135. value: Var[str]
  136. class MenuGroup(ChakraComponent):
  137. """A wrapper to group related menu items."""
  138. tag = "MenuGroup"
  139. class MenuOptionGroup(ChakraComponent):
  140. """A wrapper for checkable menu items (radio and checkbox)."""
  141. tag = "MenuOptionGroup"
  142. # "checkbox" | "radio"
  143. type_: Var[str]
  144. # Value of the option group.
  145. value: Var[str]
  146. class MenuDivider(ChakraComponent):
  147. """A visual separator for menu items and groups."""
  148. tag = "MenuDivider"