summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLarvan2 <[email protected]>2026-06-21 12:50:01 +0800
committerLarvan2 <[email protected]>2026-06-21 12:50:01 +0800
commit2de67ed7e2ca5bbf8c59dcad5a5e4c0d69462e86 (patch)
tree468a81061a53ffb01d3e90be870776b973a3cc6f
parent5ed61163bf6f621a16fe109119ebf4f261c26830 (diff)
refactor: replace unmaintained @reach/tooltip with Radix UI
- add a shared Tooltip wrapper around @radix-ui/react-tooltip that keeps the @reach-style `label` API, so call sites barely change - add a global RadixTooltip.Provider in AppProviders - replace the custom useTooltip/TooltipPopup positioning in Proxy.tsx with Radix auto-positioning - migrate reach tooltip CSS to a .tooltip-content class - drop @reach/visually-hidden (was unused; the visually-hidden CSS class is unrelated) Co-Authored-By: Claude Opus 4.8 <[email protected]>
-rw-r--r--package.json3
-rw-r--r--pnpm-lock.yaml430
-rw-r--r--src/app/providers.tsx5
-rw-r--r--src/components/SideBar.tsx2
-rw-r--r--src/components/proxies/Proxies.tsx2
-rw-r--r--src/components/proxies/Proxy.tsx28
-rw-r--r--src/components/shared/ThemeSwitcher.tsx2
-rw-r--r--src/components/shared/Tooltip.tsx29
-rw-r--r--src/styles/main.scss9
9 files changed, 418 insertions, 92 deletions
diff --git a/package.json b/package.json
index ca5148f..977a5ff 100644
--- a/package.json
+++ b/package.json
@@ -20,8 +20,7 @@
},
"dependencies": {
"@hello-pangea/dnd": "^18.0.1",
- "@reach/tooltip": "0.18.0",
- "@reach/visually-hidden": "0.18.0",
+ "@radix-ui/react-tooltip": "^1.2.10",
"@tanstack/react-query": "^5.101.0",
"@tanstack/react-table": "^8.21.3",
"chartjs-adapter-date-fns": "^3.0.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 42ed1f0..75f4d27 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -15,12 +15,9 @@ importers:
'@hello-pangea/dnd':
specifier: ^18.0.1
- '@reach/tooltip':
- specifier: 0.18.0
- '@reach/visually-hidden':
- specifier: 0.18.0
+ '@radix-ui/react-tooltip':
+ specifier: ^1.2.10
'@tanstack/react-query':
specifier: ^5.101.0
version: 5.101.0([email protected])
@@ -1269,6 +1266,21 @@ packages:
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@floating-ui/[email protected]':
+ resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==}
+
+ '@floating-ui/[email protected]':
+ resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==}
+
+ '@floating-ui/[email protected]':
+ resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==}
+ peerDependencies:
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+
+ '@floating-ui/[email protected]':
+ resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==}
+
'@fontsource/[email protected]':
resolution: {integrity: sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==}
@@ -1439,49 +1451,214 @@ packages:
resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
engines: {node: '>= 10.0.0'}
- '@reach/[email protected]':
- resolution: {integrity: sha512-XwY1IwhM7mkHZFghhjiqjQ6dstbOdpbFLdggeke75u8/8icT8uEHLbovFUgzKjy9qPvYwZIB87rLiR8WdtOXCg==}
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==}
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-j2VTDz1vgCsmuG0k5lBfOcM8n5JPFqZBcMryasFjHYMhwxYL5SRUV5lMSUpRdNtw3D/Sv8pzJtrlAgkssYSsQQ==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-2v+zNAWWe0ySxgC0D0yeXMPQ23xZVgXZTerTz+JKlmdRj6gfTqmCcR29jb6d290DezXPGgruHWDX/vYUebtErg==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-bhnq/0DEPTi2lsOD3J5rTL65qUKHbKbhqHsmN9TMiclSXpipi651ooUKPPp6G5lF/WiHBdn1s0Wuqsn+myVAvw==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-m309havGzsjLHHaIX50G5PlvRs3xkgPCsGk/5PTvYm8D5q33yG0J7w/712PTOhid7NTaFETtnSXjngHQavvhVw==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-NlNe8D0dWEpVfXFli90IO6X07Josx/b1iu98tDnx9Xv0HT4wLIL+m2VOheMHhK7qbp2HoTBqALEFzGyZs/levw==}
peerDependencies:
- react: ^16.8.0 || 17.x
- react-dom: ^16.8.0 || 17.x
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
- '@reach/[email protected]':
- resolution: {integrity: sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ==}
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==}
+ peerDependencies:
+ '@types/react': 18.3.28
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
- '@reach/[email protected]':
- resolution: {integrity: sha512-N9iAjdMbE//6rryZZxAPLRorzDcGBnluf7YQij6XDLiMtfCj1noa7KyLpEc/5XCIB/EwhX3zCluFAwloBKdblA==}
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==}
peerDependencies:
- react: ^16.8.0 || 17.x
+ '@types/react': 18.3.28
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
- '@reach/[email protected]':
- resolution: {integrity: sha512-TImozRapd576ofRk30Le2L3lRTFXF1p47B182wnp5eMTdZa74JX138BtNGEPJFOyrMaVmguVF8SSwZ6a0fon1Q==}
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-2uVLvLjgO7NZCWw01/FdqRwmA42J0BcjPMUCA+koFEOAb+zjqIP7SiFz/7zWPrKnVmSqr76Omq2ALyCuX4dhLw==}
peerDependencies:
- react: ^16.8.0 || 17.x
- react-dom: ^16.8.0 || 17.x
+ '@types/react': 18.3.28
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
- '@reach/[email protected]':
- resolution: {integrity: sha512-Xk8urN4NLn3F70da/DtByMow83qO6DF6vOxpLjuDBqud+kjKgxAU9vZMBSZJyH37+F8mZinRnHyXtlLn5njQOg==}
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==}
peerDependencies:
- react: ^16.8.0 || 17.x
- react-dom: ^16.8.0 || 17.x
+ '@types/react': 18.3.28
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
- '@reach/[email protected]':
- resolution: {integrity: sha512-yugoTmTjB3qoMk/nUvcnw99MqpyE2TQMOXE29qnQhSqHriRwQhfftjXlTAGTSzsUJmbyms3A/1gQW0X61kjFZw==}
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw==}
peerDependencies:
- react: ^16.8.0 || 17.x
- react-dom: ^16.8.0 || 17.x
+ '@types/react': 18.3.28
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
- '@reach/[email protected]':
- resolution: {integrity: sha512-KdVMdpTgDyK8FzdKO9SCpiibuy/kbv3pwgfXshTI6tEcQT1OOwj7BAksnzGC0rPz0UholwC+AgkqEl3EJX3M1A==}
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w==}
peerDependencies:
- react: ^16.8.0 || 17.x
- react-dom: ^16.8.0 || 17.x
+ '@types/react': 18.3.28
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
- '@reach/[email protected]':
- resolution: {integrity: sha512-NsJ3oeHJtPc6UOeV6MHMuzQ5sl1ouKhW85i3C0S7VM+klxVlYScBZ2J4UVnWB50A2c+evdVpCnld2YeuyYYwBw==}
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-jCE0WljWifTI4niIMCll06kGpsJTAPiZVU9H4WR1N6qW7At9ystHbN7dDB+we2xH535roFHj7qKS+RGj0FMDWQ==}
peerDependencies:
- react: ^16.8.0 || 17.x || 18.x
- react-dom: ^16.8.0 || 17.x || 18.x
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@radix-ui/[email protected]':
+ resolution: {integrity: sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA==}
'@rolldown/[email protected]':
resolution: {integrity: sha512-5Uxg7fQUCmfhax7FJke2+8B6cqgeUJUD9o2uXIKXhD+mG0mL6NObmVoi9wXEU1tY89mZKgAYA6fTbftx3q2ZPQ==}
@@ -5330,6 +5507,23 @@ snapshots:
'@eslint/core': 0.17.0
levn: 0.4.1
+ '@floating-ui/[email protected]':
+ dependencies:
+ '@floating-ui/utils': 0.2.11
+
+ '@floating-ui/[email protected]':
+ dependencies:
+ '@floating-ui/core': 1.7.5
+ '@floating-ui/utils': 0.2.11
+
+ dependencies:
+ '@floating-ui/dom': 1.7.6
+ react: 18.3.1
+ react-dom: 18.3.1([email protected])
+
+ '@floating-ui/[email protected]': {}
+
'@fontsource/[email protected]': {}
'@fontsource/[email protected]': {}
@@ -5478,52 +5672,180 @@ snapshots:
'@parcel/watcher-win32-x64': 2.5.6
optional: true
+ '@radix-ui/[email protected]': {}
+
+ dependencies:
+ react: 18.3.1
+ react-dom: 18.3.1([email protected])
+ optionalDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7(@types/[email protected])
+
+ dependencies:
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.28
+
dependencies:
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.28
+
+ dependencies:
+ '@radix-ui/primitive': 1.1.4
+ '@radix-ui/react-compose-refs': 1.1.3(@types/[email protected])([email protected])
+ '@radix-ui/react-use-callback-ref': 1.1.2(@types/[email protected])([email protected])
+ '@radix-ui/react-use-escape-keydown': 1.1.2(@types/[email protected])([email protected])
react: 18.3.1
react-dom: 18.3.1([email protected])
+ optionalDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7(@types/[email protected])
- '@reach/[email protected]': {}
+ dependencies:
+ '@radix-ui/react-use-layout-effect': 1.1.2(@types/[email protected])([email protected])
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.28
dependencies:
+ '@floating-ui/react-dom': 2.1.8([email protected]([email protected]))([email protected])
+ '@radix-ui/react-compose-refs': 1.1.3(@types/[email protected])([email protected])
+ '@radix-ui/react-context': 1.1.4(@types/[email protected])([email protected])
+ '@radix-ui/react-use-callback-ref': 1.1.2(@types/[email protected])([email protected])
+ '@radix-ui/react-use-layout-effect': 1.1.2(@types/[email protected])([email protected])
+ '@radix-ui/react-use-rect': 1.1.2(@types/[email protected])([email protected])
+ '@radix-ui/react-use-size': 1.1.2(@types/[email protected])([email protected])
+ '@radix-ui/rect': 1.1.2
react: 18.3.1
+ react-dom: 18.3.1([email protected])
+ optionalDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7(@types/[email protected])
dependencies:
+ '@radix-ui/react-use-layout-effect': 1.1.2(@types/[email protected])([email protected])
react: 18.3.1
react-dom: 18.3.1([email protected])
+ optionalDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7(@types/[email protected])
dependencies:
- '@reach/observe-rect': 1.2.0
+ '@radix-ui/react-use-layout-effect': 1.1.2(@types/[email protected])([email protected])
react: 18.3.1
react-dom: 18.3.1([email protected])
+ optionalDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7(@types/[email protected])
dependencies:
- '@reach/polymorphic': 0.18.0([email protected])
- '@reach/visually-hidden': 0.18.0([email protected]([email protected]))([email protected])
+ '@radix-ui/react-slot': 1.3.0(@types/[email protected])([email protected])
react: 18.3.1
react-dom: 18.3.1([email protected])
+ optionalDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7(@types/[email protected])
dependencies:
+ '@radix-ui/react-compose-refs': 1.1.3(@types/[email protected])([email protected])
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.28
+
+ dependencies:
+ '@radix-ui/primitive': 1.1.4
+ '@radix-ui/react-compose-refs': 1.1.3(@types/[email protected])([email protected])
+ '@radix-ui/react-context': 1.1.4(@types/[email protected])([email protected])
+ '@radix-ui/react-dismissable-layer': 1.1.13(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected])
+ '@radix-ui/react-id': 1.1.2(@types/[email protected])([email protected])
+ '@radix-ui/react-slot': 1.3.0(@types/[email protected])([email protected])
+ '@radix-ui/react-use-controllable-state': 1.2.3(@types/[email protected])([email protected])
+ '@radix-ui/react-visually-hidden': 1.2.6(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected])
react: 18.3.1
react-dom: 18.3.1([email protected])
+ optionalDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7(@types/[email protected])
+
+ dependencies:
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.28
+
+ dependencies:
+ '@radix-ui/react-use-effect-event': 0.0.3(@types/[email protected])([email protected])
+ '@radix-ui/react-use-layout-effect': 1.1.2(@types/[email protected])([email protected])
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.28
+
+ dependencies:
+ '@radix-ui/react-use-layout-effect': 1.1.2(@types/[email protected])([email protected])
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.28
+
+ dependencies:
+ '@radix-ui/react-use-callback-ref': 1.1.2(@types/[email protected])([email protected])
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.28
+
+ dependencies:
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.28
dependencies:
- '@reach/polymorphic': 0.18.0([email protected])
+ '@radix-ui/rect': 1.1.2
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.28
+
+ dependencies:
+ '@radix-ui/react-use-layout-effect': 1.1.2(@types/[email protected])([email protected])
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.28
+
+ dependencies:
react: 18.3.1
react-dom: 18.3.1([email protected])
+ optionalDependencies:
+ '@types/react': 18.3.28
+ '@types/react-dom': 18.3.7(@types/[email protected])
+
+ '@radix-ui/[email protected]': {}
'@rolldown/[email protected]': {}
diff --git a/src/app/providers.tsx b/src/app/providers.tsx
index 709df3b..2ad83e2 100644
--- a/src/app/providers.tsx
+++ b/src/app/providers.tsx
@@ -1,3 +1,4 @@
+import * as RadixTooltip from '@radix-ui/react-tooltip';
import { QueryClientProvider } from '@tanstack/react-query';
import * as React from 'react';
@@ -14,7 +15,9 @@ export function AppProviders({ children }: Props) {
return (
<ErrorBoundary>
<StateProvider initialState={initialState} actions={actions}>
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
+ <QueryClientProvider client={queryClient}>
+ <RadixTooltip.Provider delayDuration={0}>{children}</RadixTooltip.Provider>
+ </QueryClientProvider>
</StateProvider>
</ErrorBoundary>
);
diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx
index ffd2679..15db264 100644
--- a/src/components/SideBar.tsx
+++ b/src/components/SideBar.tsx
@@ -1,4 +1,3 @@
-import { Tooltip } from '@reach/tooltip';
import { useSuspenseQuery } from '@tanstack/react-query';
import cx from 'clsx';
import * as React from 'react';
@@ -9,6 +8,7 @@ import { Link, useLocation } from 'react-router-dom';
import { fetchVersion } from '~/api/version';
import { Info } from '~/components/shared/FeatherIcons';
import { ThemeSwitcher } from '~/components/shared/ThemeSwitcher';
+import { Tooltip } from '~/components/shared/Tooltip';
import { connect } from '~/components/StateProvider';
import { getClashAPIConfig } from '~/store/app';
import { ClashAPIConfig } from '~/types';
diff --git a/src/components/proxies/Proxies.tsx b/src/components/proxies/Proxies.tsx
index 667c990..8bd37f4 100644
--- a/src/components/proxies/Proxies.tsx
+++ b/src/components/proxies/Proxies.tsx
@@ -1,4 +1,3 @@
-import { Tooltip } from '@reach/tooltip';
import cx from 'clsx';
import * as React from 'react';
import { useTranslation } from 'react-i18next';
@@ -12,6 +11,7 @@ import { ProxyProvider } from '~/components/proxies/ProxyProvider';
import Settings from '~/components/proxies/Settings';
import BaseModal from '~/components/shared/BaseModal';
import { TextFilter } from '~/components/shared/TextFitler';
+import { Tooltip } from '~/components/shared/Tooltip';
import { useStoreActions } from '~/components/StateProvider';
import Equalizer from '~/components/svg/Equalizer';
import { useProxiesPage } from '~/modules/proxies/hooks';
diff --git a/src/components/proxies/Proxy.tsx b/src/components/proxies/Proxy.tsx
index f2de17f..dd5a38c 100644
--- a/src/components/proxies/Proxy.tsx
+++ b/src/components/proxies/Proxy.tsx
@@ -1,7 +1,7 @@
-import { TooltipPopup, useTooltip } from '@reach/tooltip';
import cx from 'clsx';
import * as React from 'react';
+import { Tooltip } from '~/components/shared/Tooltip';
import { keyCodes } from '~/misc/keycode';
import { DispatchFn, ProxyItem } from '~/store/types';
import { ClashAPIConfig } from '~/types';
@@ -131,28 +131,6 @@ function formatProxyType(t: string) {
return t;
}
-const positionProxyNameTooltip = (triggerRect: { left: number; top: number }) => {
- return {
- left: triggerRect.left + window.scrollX - 5,
- top: triggerRect.top + window.scrollY - 38,
- };
-};
-
-function ProxyNameTooltip({ children, label, 'aria-label': ariaLabel }) {
- const [trigger, tooltip] = useTooltip();
- return (
- <>
- {React.cloneElement(children, trigger)}
- <TooltipPopup
- {...tooltip}
- label={label}
- aria-label={ariaLabel}
- position={positionProxyNameTooltip}
- />
- </>
- );
-}
-
export const Proxy = memo(function Proxy({
now,
name,
@@ -233,9 +211,9 @@ export const Proxy = memo(function Proxy({
role={isSelectable ? 'menuitem' : ''}
>
<div className={cx(s0.proxyName, s0.row)}>
- <ProxyNameTooltip label={name} aria-label={`proxy name: ${name}`}>
+ <Tooltip label={name} aria-label={`proxy name: ${name}`}>
<span>{name}</span>
- </ProxyNameTooltip>
+ </Tooltip>
<span className={s0.udpType} style={{ paddingLeft: 4 }}>
{formatUdpType(proxy.udp, proxy.xudp)}
</span>
diff --git a/src/components/shared/ThemeSwitcher.tsx b/src/components/shared/ThemeSwitcher.tsx
index 9a67459..59c4c3a 100644
--- a/src/components/shared/ThemeSwitcher.tsx
+++ b/src/components/shared/ThemeSwitcher.tsx
@@ -1,8 +1,8 @@
-import { Tooltip } from '@reach/tooltip';
import { LazyMotion, domAnimation, m } from 'framer-motion';
import * as React from 'react';
import { useTranslation } from 'react-i18next';
+import { Tooltip } from '~/components/shared/Tooltip';
import { connect } from '~/components/StateProvider';
import { getTheme, switchTheme } from '~/store/app';
import { State } from '~/store/types';
diff --git a/src/components/shared/Tooltip.tsx b/src/components/shared/Tooltip.tsx
new file mode 100644
index 0000000..070dd52
--- /dev/null
+++ b/src/components/shared/Tooltip.tsx
@@ -0,0 +1,29 @@
+import * as RadixTooltip from '@radix-ui/react-tooltip';
+import * as React from 'react';
+
+// 对外保持与原 @reach/tooltip 相近的 `label` API,封装 Radix Tooltip。
+// 全局的 RadixTooltip.Provider 在 app/providers.tsx 中提供。
+export function Tooltip({
+ label,
+ children,
+ 'aria-label': ariaLabel,
+}: {
+ label: React.ReactNode;
+ children: React.ReactElement;
+ 'aria-label'?: string;
+}) {
+ return (
+ <RadixTooltip.Root>
+ <RadixTooltip.Trigger asChild>{children}</RadixTooltip.Trigger>
+ <RadixTooltip.Portal>
+ <RadixTooltip.Content
+ className="tooltip-content"
+ sideOffset={5}
+ aria-label={ariaLabel}
+ >
+ {label}
+ </RadixTooltip.Content>
+ </RadixTooltip.Portal>
+ </RadixTooltip.Root>
+ );
+}
diff --git a/src/styles/main.scss b/src/styles/main.scss
index cf04c9e..3932141 100644
--- a/src/styles/main.scss
+++ b/src/styles/main.scss
@@ -222,15 +222,10 @@ body {
padding: 0;
}
-/**** @reach/tooltip/styles.css ****/
-:root {
- --reach-tooltip: 1;
-}
-
-[data-reach-tooltip] {
+/**** Radix Tooltip content ****/
+.tooltip-content {
z-index: 1;
pointer-events: none;
- position: absolute;
padding: 0.25em 0.5em;
box-shadow: 2px 2px 10px hsla(0, 0%, 0%, 0.1);
white-space: nowrap;