Commit 7aeea29f authored by tom's avatar tom

use interactive tooltips for address highlight feature

parent 7ec9a2d6
......@@ -11,9 +11,10 @@ export interface TruncatedTextTooltipProps {
children: React.ReactNode;
label: React.ReactNode;
placement?: Placement;
interactive?: boolean;
}
export const TruncatedTextTooltip = React.memo(({ children, label, placement }: TruncatedTextTooltipProps) => {
export const TruncatedTextTooltip = React.memo(({ children, label, placement, interactive }: TruncatedTextTooltipProps) => {
const childRef = React.useRef<HTMLElement>(null);
const [ isTruncated, setTruncated ] = React.useState(false);
const { open, onToggle, onOpen, onClose } = useDisclosure();
......@@ -83,6 +84,7 @@ export const TruncatedTextTooltip = React.memo(({ children, label, placement }:
contentProps={{ maxW: { base: 'calc(100vw - 8px)', lg: '400px' } }}
positioning={{ placement }}
open={ open }
interactive={ interactive }
>
{ modifiedChildren }
</Tooltip>
......
......@@ -13,10 +13,11 @@ export interface Props extends Omit<IconButtonProps, 'type' | 'loading'> {
// Chakra v3 doesn't support tooltip inside tooltip - https://github.com/chakra-ui/chakra-ui/issues/9939#issuecomment-2817168121
// so we disable the copy tooltip manually when the button is inside a tooltip
noTooltip?: boolean;
tooltipInteractive?: boolean;
}
const CopyToClipboard = (props: Props) => {
const { text, type = 'text', isLoading, onClick, boxSize = 5, noTooltip, ...rest } = props;
const { text, type = 'text', isLoading, onClick, boxSize = 5, noTooltip, tooltipInteractive, ...rest } = props;
const { hasCopied, copy, disclosure } = useClipboard(text);
......@@ -76,6 +77,7 @@ const CopyToClipboard = (props: Props) => {
open={ disclosure.open }
onOpenChange={ disclosure.onOpenChange }
closeOnPointerDown={ false }
interactive={ tooltipInteractive }
>
{ button }
</Tooltip>
......
......@@ -7,11 +7,12 @@ import { Tooltip } from 'toolkit/chakra/tooltip';
interface Props {
hash: string;
noTooltip?: boolean;
tooltipInteractive?: boolean;
type?: 'long' | 'short';
as?: React.ElementType;
}
const HashStringShorten = ({ hash, noTooltip, as = 'span', type }: Props) => {
const HashStringShorten = ({ hash, noTooltip, as = 'span', type, tooltipInteractive }: Props) => {
const charNumber = type === 'long' ? 16 : 8;
if (hash.length <= charNumber) {
return <chakra.span as={ as }>{ hash }</chakra.span>;
......@@ -24,7 +25,7 @@ const HashStringShorten = ({ hash, noTooltip, as = 'span', type }: Props) => {
}
return (
<Tooltip content={ hash } disabled={ noTooltip }>
<Tooltip content={ hash } interactive={ tooltipInteractive }>
{ content }
</Tooltip>
);
......
......@@ -24,11 +24,12 @@ interface Props {
hash: string;
fontWeight?: string | number;
noTooltip?: boolean;
tooltipInteractive?: boolean;
tailLength?: number;
as?: React.ElementType;
}
const HashStringShortenDynamic = ({ hash, fontWeight = '400', noTooltip, tailLength = TAIL_LENGTH, as = 'span' }: Props) => {
const HashStringShortenDynamic = ({ hash, fontWeight = '400', noTooltip, tailLength = TAIL_LENGTH, as = 'span', tooltipInteractive }: Props) => {
const elementRef = useRef<HTMLSpanElement>(null);
const [ displayedString, setDisplayedString ] = React.useState(hash);
......@@ -98,6 +99,7 @@ const HashStringShortenDynamic = ({ hash, fontWeight = '400', noTooltip, tailLen
<Tooltip
content={ hash }
contentProps={{ maxW: { base: 'calc(100vw - 8px)', lg: '400px' } }}
interactive={ tooltipInteractive }
>
{ content }
</Tooltip>
......
......@@ -10,11 +10,12 @@ interface Props {
isLoading?: boolean;
value: string;
tooltipPlacement?: Placement;
tooltipInteractive?: boolean;
}
const TruncatedValue = ({ className, isLoading, value, tooltipPlacement }: Props) => {
const TruncatedValue = ({ className, isLoading, value, tooltipPlacement, tooltipInteractive }: Props) => {
return (
<TruncatedTextTooltip label={ value } placement={ tooltipPlacement }>
<TruncatedTextTooltip label={ value } placement={ tooltipPlacement } interactive={ tooltipInteractive }>
<Skeleton
className={ className }
loading={ isLoading }
......
......@@ -36,7 +36,9 @@ const Link = chakra((props: LinkProps) => {
);
});
type IconProps = Pick<EntityProps, 'address' | 'isSafeAddress'> & EntityBase.IconBaseProps;
type IconProps = Pick<EntityProps, 'address' | 'isSafeAddress'> & EntityBase.IconBaseProps & {
tooltipInteractive?: boolean;
};
const Icon = (props: IconProps) => {
if (props.noIcon) {
......@@ -70,7 +72,7 @@ const Icon = (props: IconProps) => {
const label = (isVerified ? 'verified ' : '') + (isProxy ? 'proxy contract' : 'contract');
return (
<Tooltip content={ label.slice(0, 1).toUpperCase() + label.slice(1) }>
<Tooltip content={ label.slice(0, 1).toUpperCase() + label.slice(1) } interactive={ props.tooltipInteractive }>
<span>
<EntityBase.Icon
{ ...props }
......@@ -90,7 +92,7 @@ const Icon = (props: IconProps) => {
})();
return (
<Tooltip content={ label } disabled={ !label }>
<Tooltip content={ label } disabled={ !label } interactive={ props.tooltipInteractive }>
<Flex marginRight={ styles.marginRight } position="relative">
<AddressIdenticon
size={ props.variant === 'heading' ? 30 : 20 }
......@@ -128,7 +130,12 @@ const Content = chakra((props: ContentProps) => {
);
return (
<Tooltip content={ label } contentProps={{ maxW: { base: 'calc(100vw - 8px)', lg: '400px' } }} triggerProps={{ minW: 0 }}>
<Tooltip
content={ label }
contentProps={{ maxW: { base: 'calc(100vw - 8px)', lg: '400px' } }}
triggerProps={{ minW: 0 }}
interactive={ props.tooltipInteractive }
>
<Skeleton loading={ props.isLoading } overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap" { ...styles }>
{ nameText }
</Skeleton>
......@@ -174,7 +181,10 @@ const AddressEntity = (props: EntityProps) => {
const settingsContext = useSettingsContext();
const altHash = !props.noAltHash && settingsContext?.addressFormat === 'bech32' ? toBech32Address(props.address.hash) : undefined;
const content = <Content { ...partsProps.content } altHash={ altHash }/>;
// inside highlight context all tooltips should be interactive
// because non-interactive ones will not pass 'onMouseLeave' event to the parent component
// see issue - https://github.com/chakra-ui/chakra-ui/issues/9939#issuecomment-2810567024
const content = <Content { ...partsProps.content } altHash={ altHash } tooltipInteractive={ Boolean(highlightContext) }/>;
return (
<Container
......@@ -187,9 +197,9 @@ const AddressEntity = (props: EntityProps) => {
position="relative"
zIndex={ 0 }
>
<Icon { ...partsProps.icon }/>
<Icon { ...partsProps.icon } tooltipInteractive={ Boolean(highlightContext) }/>
{ props.noLink ? content : <Link { ...partsProps.link }>{ content }</Link> }
<Copy { ...partsProps.copy } altHash={ altHash }/>
<Copy { ...partsProps.copy } altHash={ altHash } tooltipInteractive={ Boolean(highlightContext) }/>
</Container>
);
};
......
......@@ -115,9 +115,20 @@ const Icon = ({ isLoading, noIcon, variant, name, color, borderRadius, marginRig
export interface ContentBaseProps extends Pick<EntityBaseProps, 'className' | 'isLoading' | 'truncation' | 'tailLength' | 'noTooltip' | 'variant'> {
asProp?: React.ElementType;
text: string;
tooltipInteractive?: boolean;
}
const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dynamic', tailLength, noTooltip, variant }: ContentBaseProps) => {
const Content = chakra(({
className,
isLoading,
asProp,
text,
truncation = 'dynamic',
tailLength,
variant,
noTooltip,
tooltipInteractive,
}: ContentBaseProps) => {
const styles = getContentProps(variant);
if (truncation === 'tail') {
......@@ -126,6 +137,7 @@ const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dyna
className={ className }
isLoading={ isLoading }
value={ text }
tooltipInteractive={ tooltipInteractive }
{ ...styles }
/>
);
......@@ -140,6 +152,7 @@ const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dyna
as={ asProp }
type="long"
noTooltip={ noTooltip }
tooltipInteractive={ tooltipInteractive }
/>
);
case 'constant':
......@@ -148,6 +161,7 @@ const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dyna
hash={ text }
as={ asProp }
noTooltip={ noTooltip }
tooltipInteractive={ tooltipInteractive }
/>
);
case 'dynamic':
......@@ -157,6 +171,7 @@ const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dyna
as={ asProp }
tailLength={ tailLength }
noTooltip={ noTooltip }
tooltipInteractive={ tooltipInteractive }
/>
);
case 'none':
......@@ -178,7 +193,10 @@ const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dyna
);
});
export type CopyBaseProps = Pick<CopyToClipboardProps, 'isLoading' | 'text'> & Pick<EntityBaseProps, 'noCopy' | 'noTooltip'>;
export type CopyBaseProps =
Pick<CopyToClipboardProps, 'isLoading' | 'text' | 'tooltipInteractive'> &
Pick<EntityBaseProps, 'noCopy' | 'noTooltip'>
;
const Copy = ({ noCopy, ...props }: CopyBaseProps) => {
if (noCopy) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment