diff --git a/package-lock.json b/package-lock.json index c600b79b8..4c2b651d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,6 +53,7 @@ "react-player": "^2.16.0", "react-redux": "8.0.5", "react-router-dom": "6.28.0", + "react-tiny-popover": "^8.1.4", "react-virtualized": "^9.22.5", "redux": "4.2.1", "redux-saga": "1.2.3", @@ -24658,6 +24659,15 @@ "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", "dev": true }, + "node_modules/react-tiny-popover": { + "version": "8.1.4", + "resolved": "https://registry.npmjs.org/react-tiny-popover/-/react-tiny-popover-8.1.4.tgz", + "integrity": "sha512-rHNAosGfUwlkOQeTJ+fCX/lHUOuMmgQZVhtRBnU9DqAONgltSv1QIZHeG1FGvZIGg7y7wbV4H6wriDuiSssIfQ==", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -48171,6 +48181,12 @@ } } }, + "react-tiny-popover": { + "version": "8.1.4", + "resolved": "https://registry.npmjs.org/react-tiny-popover/-/react-tiny-popover-8.1.4.tgz", + "integrity": "sha512-rHNAosGfUwlkOQeTJ+fCX/lHUOuMmgQZVhtRBnU9DqAONgltSv1QIZHeG1FGvZIGg7y7wbV4H6wriDuiSssIfQ==", + "requires": {} + }, "react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", diff --git a/package.json b/package.json index d64bda53e..8ebc5e45b 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "react-player": "^2.16.0", "react-redux": "8.0.5", "react-router-dom": "6.28.0", + "react-tiny-popover": "^8.1.4", "react-virtualized": "^9.22.5", "redux": "4.2.1", "redux-saga": "1.2.3", diff --git a/src/libs/ui/components/account-list/account-list-item.tsx b/src/libs/ui/components/account-list/account-list-item.tsx index c0024fec4..cef60ca37 100644 --- a/src/libs/ui/components/account-list/account-list-item.tsx +++ b/src/libs/ui/components/account-list/account-list-item.tsx @@ -1,6 +1,6 @@ import { formatNumber } from 'casper-wallet-core'; import { IAccountInfo } from 'casper-wallet-core/src/domain/accountInfo'; -import React from 'react'; +import React, { useRef } from 'react'; import styled from 'styled-components'; import { @@ -72,6 +72,8 @@ export const AccountListItem = ({ accountLiquidBalance, isLoadingBalance }: AccountListItemProps) => { + const popoverParentRef = useRef(null); + const accountBalance = accountLiquidBalance ? formatNumber(motesToCSPR(accountLiquidBalance), { precision: { max: 0 } @@ -83,7 +85,7 @@ export const AccountListItem = ({ accountsInfo && accountsInfo[account.accountHash]?.brandingLogo; return ( - + diff --git a/src/libs/ui/components/account-popover/account-popover.tsx b/src/libs/ui/components/account-popover/account-popover.tsx index 9eaaa8fc8..b31bcbbd8 100644 --- a/src/libs/ui/components/account-popover/account-popover.tsx +++ b/src/libs/ui/components/account-popover/account-popover.tsx @@ -1,6 +1,7 @@ -import React from 'react'; +import React, { useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; +import styled from 'styled-components'; import { getBlockExplorerAccountUrl } from '@src/constants'; @@ -16,20 +17,33 @@ import { selectIsAnyAccountConnectedWithActiveOrigin } from '@background/redux/vault/selectors'; +import { FlexColumn } from '@libs/layout'; import { Account } from '@libs/types/account'; import { PopoverLink, SvgIcon, Typography } from '@libs/ui/components'; import { Popover } from '@libs/ui/components/popover/popover'; +const PopoverItemsContainer = styled(FlexColumn)` + padding: 8px; + + background: ${({ theme }) => theme.color.backgroundPrimary}; + box-shadow: ${({ theme }) => theme.shadow.contextMenu}; + border-radius: ${({ theme }) => theme.borderRadius.eight}px; +`; + interface AccountActionsMenuPopoverProps { account: Account; onClick?: (e: React.MouseEvent) => void; showHideAccountItem?: boolean; + popoverParentRef: React.MutableRefObject; } export const AccountActionsMenuPopover = ({ account, onClick, - showHideAccountItem + showHideAccountItem, + popoverParentRef }: AccountActionsMenuPopoverProps) => { + const [isOpen, setIsOpen] = useState(false); + const navigate = useTypedNavigate(); const { t } = useTranslation(); const { disconnectAccountWithEvent: disconnectAccount } = useAccountManager(); @@ -44,13 +58,16 @@ export const AccountActionsMenuPopover = ({ return ( ( - <> + popoverParentRef={popoverParentRef} + isOpen={isOpen} + setIsOpen={setIsOpen} + content={() => ( + {connectedAccountNames.includes(account.name) ? ( { - closePopover(event); + setIsOpen(false); activeOrigin && disconnectAccount(account.name, activeOrigin); if (onClick) { @@ -176,10 +193,10 @@ export const AccountActionsMenuPopover = ({ Manage - + )} > - + setIsOpen(!isOpen)} /> ); }; diff --git a/src/libs/ui/components/popover/popover.tsx b/src/libs/ui/components/popover/popover.tsx index 38376b20a..52a5ccb43 100644 --- a/src/libs/ui/components/popover/popover.tsx +++ b/src/libs/ui/components/popover/popover.tsx @@ -1,102 +1,61 @@ -import React, { MouseEvent, PropsWithChildren, useRef, useState } from 'react'; -import styled from 'styled-components'; - -import { useClickAway } from '@hooks/use-click-away'; - -import { AlignedFlexRow, FlexColumn, Overlay, SpacingSize } from '@libs/layout'; - -const popoverOffsetFromChildren = 8; -const contentHeight = 188; - -const ChildrenContainer = styled(AlignedFlexRow)` - cursor: pointer; -`; - -interface PopoverContainerProps { - domRect?: DOMRect; -} - -const PopoverOverlay = styled(Overlay)` - background: inherit; -`; - -const PopoverContainer = styled.div` - position: absolute; - right: 16px; - top: ${({ domRect }) => { - if (domRect == null) { - return '0px'; - } - - const { top, bottom, height } = domRect; - - if (top && bottom) { - return bottom >= window.innerHeight - contentHeight - ? `${top - contentHeight}px` - : `${top + height + popoverOffsetFromChildren}px`; - } - }}; - - z-index: ${({ theme }) => theme.zIndex.dropdown}; -`; - -const PopoverItemsContainer = styled(FlexColumn)` - padding: 8px; - - background: ${({ theme }) => theme.color.backgroundPrimary}; - box-shadow: ${({ theme }) => theme.shadow.contextMenu}; - border-radius: ${({ theme }) => theme.borderRadius.eight}px; -`; - -type RenderProps = { - closePopover: (e: MouseEvent) => void; -}; +import React, { PropsWithChildren, useEffect } from 'react'; +import { ContentRenderer, Popover as TinyPopover } from 'react-tiny-popover'; interface PopoverProps { - renderMenuItems: (renderProps: RenderProps) => JSX.Element; + content: ContentRenderer; + popoverParentRef: React.MutableRefObject; + children: JSX.Element; + isOpen: boolean; + setIsOpen: React.Dispatch>; } export function Popover({ - renderMenuItems, - children + content, + children, + popoverParentRef, + isOpen, + setIsOpen }: PropsWithChildren) { - const [isOpen, setIsOpen] = useState(false); - const childrenContainerRef = useRef(null); - - const { ref: clickAwayRef } = useClickAway({ - callback: (event: MouseEvent) => { - event.stopPropagation(); - isOpen && setIsOpen(false); + useEffect(() => { + // Get the container with class "ms-container" + // (to manage scroll behavior while the popover is open) + const scrollableContainer = document.querySelector('.ms-container'); + if (scrollableContainer) { + const style = scrollableContainer.getAttribute('style'); + if (isOpen) { + scrollableContainer.setAttribute('style', `${style} overflow: hidden;`); + } else { + scrollableContainer.setAttribute( + 'style', + style?.replace('overflow: hidden;', '')! + ); + } } - }); - const closePopover = (e: MouseEvent) => { - e.stopPropagation(); - setIsOpen(false); - }; + return () => { + if (scrollableContainer) { + const style = scrollableContainer.getAttribute('style'); + scrollableContainer.setAttribute( + 'style', + style?.replace('overflow: hidden;', '')! + ); + } + }; + }, [isOpen]); return ( - <> - setIsOpen(true)} - > - {children} - - - {isOpen && ( - - - - {renderMenuItems({ closePopover })} - - - - )} - + setIsOpen(false)} + positions={['bottom', 'top']} + containerStyle={{ + zIndex: '15' + }} + transform={{ top: 55, left: 135 }} + parentElement={popoverParentRef.current || undefined} + content={content} + > + {children} + ); }