Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
7aeea29f
Commit
7aeea29f
authored
Apr 22, 2025
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
use interactive tooltips for address highlight feature
parent
7ec9a2d6
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
52 additions
and
16 deletions
+52
-16
TruncatedTextTooltip.tsx
toolkit/components/truncation/TruncatedTextTooltip.tsx
+3
-1
CopyToClipboard.tsx
ui/shared/CopyToClipboard.tsx
+3
-1
HashStringShorten.tsx
ui/shared/HashStringShorten.tsx
+3
-2
HashStringShortenDynamic.tsx
ui/shared/HashStringShortenDynamic.tsx
+3
-1
TruncatedValue.tsx
ui/shared/TruncatedValue.tsx
+3
-2
AddressEntity.tsx
ui/shared/entities/address/AddressEntity.tsx
+17
-7
components.tsx
ui/shared/entities/base/components.tsx
+20
-2
No files found.
toolkit/components/truncation/TruncatedTextTooltip.tsx
View file @
7aeea29f
...
...
@@ -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
>
...
...
ui/shared/CopyToClipboard.tsx
View file @
7aeea29f
...
...
@@ -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
>
...
...
ui/shared/HashStringShorten.tsx
View file @
7aeea29f
...
...
@@ -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
>
);
...
...
ui/shared/HashStringShortenDynamic.tsx
View file @
7aeea29f
...
...
@@ -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
>
...
...
ui/shared/TruncatedValue.tsx
View file @
7aeea29f
...
...
@@ -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
}
...
...
ui/shared/entities/address/AddressEntity.tsx
View file @
7aeea29f
...
...
@@ -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
>
);
};
...
...
ui/shared/entities/base/components.tsx
View file @
7aeea29f
...
...
@@ -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
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment