diff --git a/README.md b/README.md
index 5cdc041..b628e82 100644
--- a/README.md
+++ b/README.md
@@ -20,3 +20,7 @@ export default () => (
/>
)
```
+
+## Port Hover Tooltip
+
+If the SVG generated by `circuit-to-svg` includes `data-schematic-port-id` attributes, the viewer will display the port's name when you hover over a schematic port.
diff --git a/lib/components/SchematicViewer.tsx b/lib/components/SchematicViewer.tsx
index 1e9a2c8..c67e985 100644
--- a/lib/components/SchematicViewer.tsx
+++ b/lib/components/SchematicViewer.tsx
@@ -19,6 +19,7 @@ import { EditIcon } from "./EditIcon"
import { GridIcon } from "./GridIcon"
import type { CircuitJson } from "circuit-json"
import { zIndexMap } from "../utils/z-index-map"
+import { useSchematicPortHover } from "../hooks/useSchematicPortHover"
interface Props {
circuitJson: CircuitJson
@@ -189,6 +190,11 @@ export const SchematicViewer = ({
editEvents: editEventsWithUnappliedEditEvents,
})
+ const hoverData = useSchematicPortHover({
+ svgDivRef,
+ circuitJson,
+ })
+
const svgDiv = useMemo(
() => (
)}
{svgDiv}
+ {hoverData && (
+
+ {hoverData.name}
+
+ )}
)
}
diff --git a/lib/hooks/useSchematicPortHover.ts b/lib/hooks/useSchematicPortHover.ts
new file mode 100644
index 0000000..c23b3f6
--- /dev/null
+++ b/lib/hooks/useSchematicPortHover.ts
@@ -0,0 +1,65 @@
+import { useEffect, useState } from "react"
+import { su } from "@tscircuit/soup-util"
+import type { CircuitJson } from "circuit-json"
+
+export interface HoverData {
+ name: string
+ x: number
+ y: number
+}
+
+export const useSchematicPortHover = ({
+ svgDivRef,
+ circuitJson,
+}: {
+ svgDivRef: React.RefObject
+ circuitJson: CircuitJson
+}) => {
+ const [hover, setHover] = useState(null)
+
+ useEffect(() => {
+ const svgDiv = svgDivRef.current
+ if (!svgDiv) return
+
+ const handleMouseOver = (e: MouseEvent) => {
+ const target = e.target as Element | null
+ if (!target) return
+ const portGroup = target.closest(
+ "[data-schematic-port-id]",
+ ) as SVGGraphicsElement | null
+ if (!portGroup) return
+ const schPortId = portGroup.getAttribute("data-schematic-port-id")
+ if (!schPortId) return
+ const schPort = su(circuitJson).schematic_port.get(schPortId)
+ if (!schPort) return
+ const srcPort = su(circuitJson).source_port.get(schPort.source_port_id)
+ if (!srcPort) return
+ const rect = portGroup.getBoundingClientRect()
+ setHover({
+ name: srcPort.name || "",
+ x: rect.x + rect.width / 2,
+ y: rect.y,
+ })
+ }
+
+ const handleMouseOut = (e: MouseEvent) => {
+ const target = e.target as Element | null
+ if (!target) return
+ if (
+ target.closest("[data-schematic-port-id]") &&
+ !svgDiv.contains(e.relatedTarget as Node)
+ ) {
+ setHover(null)
+ }
+ }
+
+ svgDiv.addEventListener("mouseover", handleMouseOver)
+ svgDiv.addEventListener("mouseout", handleMouseOut)
+ return () => {
+ svgDiv.removeEventListener("mouseover", handleMouseOver)
+ svgDiv.removeEventListener("mouseout", handleMouseOut)
+ }
+ }, [svgDivRef, circuitJson])
+
+ return hover
+}
diff --git a/lib/utils/z-index-map.ts b/lib/utils/z-index-map.ts
index 891151e..c4472ed 100644
--- a/lib/utils/z-index-map.ts
+++ b/lib/utils/z-index-map.ts
@@ -2,4 +2,5 @@ export const zIndexMap = {
schematicEditIcon: 50,
schematicGridIcon: 49,
clickToInteractOverlay: 100,
+ tooltip: 101,
}