topmenu.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { useContext, useState } from 'react'
  2. import { Platform } from 'react-native'
  3. import { View, Row } from 'app/design/view'
  4. import Link from 'app/ui/atoms/link'
  5. import { Text } from 'app/design/typography'
  6. import { Icon } from 'app/ui/atoms/icon'
  7. import Tooltip from 'app/ui/atoms/tooltip'
  8. import DropdownMenu, { DropdownMenuOpenContext } from 'app/ui/atoms/dropdown-menu';
  9. export default function MenuTopItem({ link, title, index, icon, isTitle, isActive, items, chevron, animated, addClassName }) {
  10. return items?.length > 0 ?
  11. <DropdownMenu
  12. mode="popup"
  13. triggerAccessibilityLabel={title}
  14. triggerClassName="group"
  15. items={items}
  16. defaultOpen={false}
  17. >
  18. <MenuTopItem_ title={title} icon={icon} isTitle={isTitle} isActive={isActive} isPopup={true} chevron={chevron} animated={animated} addClassName={addClassName} />
  19. </DropdownMenu>
  20. : <Link variant="text" size="lg" className=" min-w-16 w-full flex-auto relative group web:active:scale-95 web:duration-100 " href={link} alt={title}>
  21. <MenuTopItem_ title={title} icon={icon} isTitle={isTitle} isActive={isActive} isPopup={false} chevron={chevron} animated={animated} addClassName={addClassName} />
  22. </Link>
  23. }
  24. function MenuTopItem_({ title, icon, isTitle, isActive, isPopup, chevron, animated, addClassName }) {
  25. const isMenuOpen = useContext(DropdownMenuOpenContext) ?? false;
  26. const isOpen = isPopup && isMenuOpen;
  27. const isActiveOrOpen = isActive || isOpen;
  28. const useAnimatedIcon = animated === true;
  29. const [groupHovered, setGroupHovered] = useState(false);
  30. const rowHoverProps =
  31. useAnimatedIcon && Platform.OS === 'web'
  32. ? {
  33. onMouseEnter: () => setGroupHovered(true),
  34. onMouseLeave: () => setGroupHovered(false),
  35. }
  36. : {};
  37. const baseIconClass = isActiveOrOpen
  38. ? 'text-accent-foreground h-9 w-9 my-auto items-center justify-center flex'
  39. : 'text-secondary-foreground web:group-hover:text-foreground h-9 w-9 items-center justify-center flex';
  40. const menuIconClassName = addClassName ? `${baseIconClass} ${addClassName}` : baseIconClass;
  41. // The hover label exists to name icon-only items. When the title is already
  42. // rendered next to the icon it just repeats it, so skip the tooltip.
  43. const showTooltip = !isTitle && !!title;
  44. return (
  45. <Tooltip content={title} enabled={showTooltip}>
  46. {/* The active link's highlight is MenuTop's sliding indicator, which never moves to a
  47. dropdown, so an open dropdown draws its own fill behind the accent-foreground label. */}
  48. <Row
  49. className={`items-center content-center justify-center px-2 h-12 min-w-16 flex-auto flex-wrap rounded-xl ${isOpen
  50. ? ' bg-accent text-accent-foreground'
  51. : isActive
  52. ? ' text-accent-foreground'
  53. : ' text-secondary-foreground web:group-hover:text-foreground web:hover:bg-muted/50 web:group-focus:bg-muted/50 web:active:bg-muted '
  54. }`}
  55. {...rowHoverProps}
  56. >
  57. {[
  58. icon ? (
  59. <Icon
  60. key="menu-icon"
  61. icon={icon}
  62. animated={useAnimatedIcon}
  63. active={useAnimatedIcon ? isActiveOrOpen : undefined}
  64. size={useAnimatedIcon ? 24 : undefined}
  65. className={menuIconClassName}
  66. hovered={useAnimatedIcon && Platform.OS === 'web' ? groupHovered : undefined}
  67. />
  68. ) : null,
  69. isTitle ? (
  70. <Text key="menu-title" className={`whitespace-nowrap text-ellipsis overflow-hidden tracking-tight font-medium ${isActiveOrOpen ? 'text-accent-foreground' : 'text-secondary-foreground'} text-sm lg:text-base px-2 leading-5`}>{title}</Text>
  71. ) : null,
  72. chevron ? (
  73. // Sized explicitly: without width and height the SVG is 24 px tall and sits
  74. // 4 px below the label. A class turns it, because NEO's web View drops
  75. // React Native transform arrays.
  76. <View
  77. key="menu-chevron"
  78. className={`h-4 w-4 items-center justify-center flex shrink-0 web:transition-transform web:duration-200 ${isOpen ? 'rotate-180' : ''}`}
  79. >
  80. <Icon
  81. icon={chevron}
  82. width={16}
  83. height={16}
  84. className={`h-4 w-4 ${isActiveOrOpen ? 'text-accent-foreground' : 'text-secondary-foreground web:group-hover:text-foreground'}`}
  85. />
  86. </View>
  87. ) : null,
  88. ]}
  89. </Row>
  90. </Tooltip>
  91. )
  92. }