Skip to content

Commit 11b456b

Browse files
create a new interactive tooltip (#2776)
* liquid mainnet * hyperloquid mainnet only * create a new interactive tooltip * Update ChainHero.tsx * refactor --------- Co-authored-by: aelmanaa <aelmanaa@gmail.com> Co-authored-by: Amine E. <aelmanaa@users.noreply.github.com>
1 parent 77e53e3 commit 11b456b

File tree

6 files changed

+493
-29
lines changed

6 files changed

+493
-29
lines changed

src/components/CCIP/ChainHero/ChainHero.tsx

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
fallbackTokenIconUrl,
1414
} from "~/features/utils/index.ts"
1515
import { Tooltip } from "~/features/common/Tooltip/Tooltip.tsx"
16+
import { getChainTooltip } from "../Tooltip/index.ts"
1617
import { ExplorerInfo, ChainType } from "@config/types.ts"
1718

1819
interface ChainHeroProps {
@@ -55,6 +56,9 @@ interface ChainHeroProps {
5556
}
5657

5758
function ChainHero({ chains, tokens, network, token, environment, lanes }: ChainHeroProps) {
59+
// Get chain-specific tooltip configuration
60+
const chainTooltipConfig = network?.chain ? getChainTooltip(network.chain) : null
61+
5862
const feeTokensWithAddress =
5963
network?.feeTokens?.map((feeToken) => {
6064
const logo = feeToken.logo
@@ -89,6 +93,8 @@ function ChainHero({ chains, tokens, network, token, environment, lanes }: Chain
8993
})
9094
}
9195

96+
console.log(JSON.stringify(network))
97+
9298
return (
9399
<section className="ccip-chain-hero">
94100
<div className="ccip-chain-hero__content">
@@ -122,8 +128,25 @@ function ChainHero({ chains, tokens, network, token, environment, lanes }: Chain
122128
currentTarget.src = fallbackTokenIconUrl
123129
}}
124130
/>
125-
<h1>
126-
{network?.name || token?.id} <span className="ccip-chain-hero__token-logo__symbol">{token?.name}</span>
131+
<h1
132+
style={{
133+
display: "flex",
134+
alignItems: "center",
135+
gap: "8px",
136+
position: "relative",
137+
overflow: "visible",
138+
}}
139+
>
140+
{network?.name || token?.id}
141+
<span className="ccip-chain-hero__token-logo__symbol">{token?.name}</span>
142+
143+
{chainTooltipConfig && (
144+
<Tooltip
145+
tip={chainTooltipConfig.content}
146+
hoverable={chainTooltipConfig.hoverable}
147+
hideDelay={chainTooltipConfig.hideDelay}
148+
/>
149+
)}
127150
</h1>
128151
</div>
129152
{network && (
@@ -139,7 +162,7 @@ function ChainHero({ chains, tokens, network, token, environment, lanes }: Chain
139162
Chain selector
140163
<Tooltip
141164
label=""
142-
tip="CCIP Blockchain identifier"
165+
tip="CCIP Blockchain identifier."
143166
labelStyle={{
144167
marginRight: "8px",
145168
}}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* @fileoverview CCIP Chain-Specific Tooltip Configuration
3+
*
4+
* Centralized configuration for chain-specific tooltips displayed in the CCIP directory.
5+
* This approach provides:
6+
* - Type safety with TypeScript
7+
* - Stable chain ID references (not display names)
8+
* - Easy content updates without code changes
9+
* - Scalable for adding new chains
10+
* - Separation of content from component logic
11+
*
12+
* @example
13+
* ```typescript
14+
* const tooltipConfig = getChainTooltip(network.chain);
15+
* if (tooltipConfig) {
16+
* return <Tooltip tip={tooltipConfig.content} hoverable={tooltipConfig.hoverable} />
17+
* }
18+
* ```
19+
*/
20+
21+
import { type ReactNode } from "react"
22+
23+
/**
24+
* Configuration for a chain-specific tooltip
25+
*/
26+
export interface ChainTooltipConfig {
27+
/** The tooltip content (supports JSX for interactive elements) */
28+
content: ReactNode
29+
/** Whether the tooltip should be hoverable (for interactive content) */
30+
hoverable: boolean
31+
/** Optional custom hide delay for hoverable tooltips */
32+
hideDelay?: number
33+
}
34+
35+
/**
36+
* Chain-specific tooltip configurations mapped by stable chain IDs.
37+
*
38+
* **Adding a new chain tooltip:**
39+
* 1. Add the chain ID as a key (use network.chain, not network.name)
40+
* 2. Provide content and interaction settings
41+
* 3. Use hoverable=true for content with links
42+
*
43+
* **Content Guidelines:**
44+
* - Keep tooltips concise and actionable
45+
* - Use JSX for links and formatting
46+
* - Test on mobile for long content
47+
*/
48+
export const CHAIN_TOOLTIPS: Record<string, ChainTooltipConfig> = {
49+
"hyperliquid-mainnet": {
50+
content: (
51+
<>
52+
Before using or integrating HyperEVM on CCIP, it is recommended to review{" "}
53+
<a href="/ccip/service-limits/network-specific-limits">Network-Specific Service Limits</a>.
54+
</>
55+
),
56+
hoverable: true,
57+
hideDelay: 300,
58+
},
59+
60+
// Example: Add more chains as needed
61+
// "abstract-mainnet": {
62+
// content: (
63+
// <>
64+
// Abstract requires special configuration. See{" "}
65+
// <a href="/ccip/abstract-setup">setup guide</a> for details.
66+
// </>
67+
// ),
68+
// hoverable: true,
69+
// },
70+
71+
// "polygon-mainnet": {
72+
// content: "Polygon CCIP integration is fully supported with standard configuration.",
73+
// hoverable: false,
74+
// },
75+
} as const
76+
77+
/**
78+
* Gets the tooltip configuration for a specific chain.
79+
*
80+
* @param chainId - The stable chain identifier (e.g., 'hyperliquid-mainnet')
81+
* @returns Tooltip configuration if exists, null otherwise
82+
*
83+
* @example
84+
* ```typescript
85+
* const tooltipConfig = getChainTooltip(network.chain);
86+
* if (tooltipConfig) {
87+
* return <Tooltip tip={tooltipConfig.content} hoverable={tooltipConfig.hoverable} />
88+
* }
89+
* ```
90+
*/
91+
export function getChainTooltip(chainId: string): ChainTooltipConfig | null {
92+
return CHAIN_TOOLTIPS[chainId] || null
93+
}
94+
95+
/**
96+
* Gets all chain IDs that have tooltip configurations.
97+
* Useful for debugging or administrative purposes.
98+
*
99+
* @returns Array of chain IDs with configured tooltips
100+
*/
101+
export function getTooltipEnabledChains(): string[] {
102+
return Object.keys(CHAIN_TOOLTIPS)
103+
}
104+
105+
/**
106+
* Type guard to check if a chain has a tooltip configuration.
107+
*
108+
* @param chainId - The chain identifier to check
109+
* @returns True if the chain has a tooltip configuration
110+
*/
111+
export function hasChainTooltip(chainId: string): boolean {
112+
return chainId in CHAIN_TOOLTIPS
113+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @fileoverview CCIP Tooltip Components and Configuration
3+
*
4+
* Centralized exports for all CCIP tooltip-related functionality.
5+
*/
6+
7+
// Re-export chain tooltip configuration
8+
export { getChainTooltip, getTooltipEnabledChains, hasChainTooltip, type ChainTooltipConfig } from "./chainTooltips.tsx"
9+
10+
// Re-export tooltip components
11+
export { default as RateTooltip } from "./RateTooltip.tsx"

src/config/data/chains.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,7 @@
13331333
"chains": {
13341334
"HYPERLIQUID_MAINNET": {
13351335
"chainId": 999,
1336-
"title": "Hyperliquid Mainnet",
1336+
"title": "Hyperliquid",
13371337
"explorer": {
13381338
"baseUrl": "https://app.hyperliquid.xyz/explorer"
13391339
},
@@ -2025,7 +2025,7 @@
20252025
"chains": {
20262026
"GRAVITY_MAINNET": {
20272027
"chainId": 1625,
2028-
"title": "Gravity Alpha Mainnet",
2028+
"title": "Gravity Alpha",
20292029
"explorer": {
20302030
"baseUrl": "https://explorer.gravity.xyz"
20312031
},
@@ -2056,7 +2056,7 @@
20562056
"chains": {
20572057
"OPBNB_MAINNET": {
20582058
"chainId": 204,
2059-
"title": "opBNB Mainnet",
2059+
"title": "opBNB",
20602060
"explorer": {
20612061
"baseUrl": "https://mainnet.opbnbscan.com"
20622062
},
@@ -2087,7 +2087,7 @@
20872087
"chains": {
20882088
"ETHERLINK_MAINNET": {
20892089
"chainId": 42793,
2090-
"title": "Etherlink Mainnet",
2090+
"title": "Etherlink",
20912091
"explorer": {
20922092
"baseUrl": "https://explorer.etherlink.com"
20932093
},
@@ -2118,7 +2118,7 @@
21182118
"chains": {
21192119
"JANCTION_MAINNET": {
21202120
"chainId": 678,
2121-
"title": "Janction Mainnet",
2121+
"title": "Janction",
21222122
"explorer": {
21232123
"baseUrl": ""
21242124
},
@@ -2149,7 +2149,7 @@
21492149
"chains": {
21502150
"NEO_X_MAINNET": {
21512151
"chainId": 47763,
2152-
"title": "Neo X Mainnet",
2152+
"title": "Neo X",
21532153
"explorer": {
21542154
"baseUrl": "https://xexplorer.neo.org"
21552155
},
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/**
2+
* CSS Module for Hoverable Tooltip Component
3+
*
4+
* Provides responsive, accessible styling for both hoverable and standard tooltip modes.
5+
* Uses CSS Grid/Flexbox for modern layout and includes mobile-first responsive design.
6+
*
7+
* Key Features:
8+
* - Responsive width calculations to prevent mobile overflow
9+
* - Proper z-index management for overlay positioning
10+
* - Accessible color contrast and focus states
11+
* - Cross-browser compatible arrow/caret styling
12+
* - CSS specificity management to override conflicting styles
13+
*
14+
* @see Tooltip.tsx for usage examples and API documentation
15+
*/
16+
17+
.container {
18+
display: flex;
19+
align-items: center;
20+
gap: 8px;
21+
position: relative;
22+
}
23+
24+
.trigger {
25+
position: relative;
26+
display: inline-block;
27+
}
28+
29+
/* More specific selector to override .ccip-chain-hero__heading img */
30+
.container .trigger .icon {
31+
width: 16px;
32+
height: 16px;
33+
min-width: 16px;
34+
min-height: 16px;
35+
max-width: 16px;
36+
max-height: 16px;
37+
object-fit: contain;
38+
display: block;
39+
cursor: pointer;
40+
}
41+
42+
.tooltip {
43+
background: black;
44+
color: #b7b7b7;
45+
border-radius: 8px;
46+
font-size: 0.75rem;
47+
font-family: inherit;
48+
font-weight: 400;
49+
line-height: 1.5;
50+
white-space: normal;
51+
text-align: left;
52+
box-shadow:
53+
0 4px 12px rgba(0, 0, 0, 0.5),
54+
0 0 0 1px #000000;
55+
border: none;
56+
outline: none;
57+
z-index: 9999;
58+
position: absolute;
59+
bottom: 100%;
60+
left: 50%;
61+
transform: translateX(-50%);
62+
margin-bottom: 10px;
63+
pointer-events: auto;
64+
overflow-wrap: break-word;
65+
word-break: break-word;
66+
67+
/* Responsive width */
68+
width: min(280px, calc(100vw - 32px));
69+
max-width: 300px;
70+
padding: 12px 8px;
71+
}
72+
73+
.caret {
74+
position: absolute;
75+
bottom: -6px;
76+
left: 50%;
77+
transform: translateX(-50%);
78+
width: 0;
79+
height: 0;
80+
border-left: 6px solid transparent;
81+
border-right: 6px solid transparent;
82+
border-top: 6px solid black;
83+
}
84+
85+
/* Mobile responsive adjustments */
86+
@media (max-width: 768px) {
87+
.tooltip {
88+
width: min(260px, calc(100vw - 16px));
89+
padding: 10px 6px;
90+
font-size: 0.7rem;
91+
margin-bottom: 8px;
92+
}
93+
94+
.caret {
95+
bottom: -5px;
96+
border-left: 5px solid transparent;
97+
border-right: 5px solid transparent;
98+
border-top: 5px solid black;
99+
}
100+
}
101+
102+
/* Small mobile adjustments */
103+
@media (max-width: 480px) {
104+
.tooltip {
105+
width: calc(100vw - 24px);
106+
max-width: 240px;
107+
padding: 8px 6px;
108+
}
109+
}
110+
111+
/* Prevent tooltip from going off-screen on left/right */
112+
@media (max-width: 320px) {
113+
.tooltip {
114+
left: 16px;
115+
right: 16px;
116+
width: auto;
117+
transform: none;
118+
}
119+
120+
.caret {
121+
left: 50%;
122+
transform: translateX(-50%);
123+
}
124+
}
125+
126+
/* Default tooltip styles (for Chainlink component) */
127+
.defaultContainer {
128+
display: flex;
129+
align-items: center;
130+
justify-content: center;
131+
}
132+
133+
.defaultIcon {
134+
width: 16px;
135+
height: 16px;
136+
min-width: 16px;
137+
min-height: 16px;
138+
object-fit: contain;
139+
display: block;
140+
}
141+
142+
.defaultText {
143+
margin-right: 2%;
144+
}
145+
146+
/* Link styling within tooltip content */
147+
.tooltip :global(.tooltip-content) a {
148+
color: #639cff;
149+
text-decoration: none;
150+
}
151+
152+
.tooltip :global(.tooltip-content) a:hover {
153+
text-decoration: underline;
154+
}

0 commit comments

Comments
 (0)