Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: disable "mouse hover focuses PCB viewer" by default #141

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/PCBViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Props = {
editEvents?: EditEvent[]
initialState?: Partial<StateProps>
onEditEventsChanged?: (editEvents: EditEvent[]) => void
focusOnHover?: boolean
}

export const PCBViewer = ({
Expand All @@ -34,6 +35,7 @@ export const PCBViewer = ({
allowEditing = true,
editEvents: editEventsProp,
onEditEventsChanged,
focusOnHover = false,
}: Props) => {
circuitJson ??= soup
const {
Expand Down Expand Up @@ -123,6 +125,7 @@ export const PCBViewer = ({
height={height}
width={refDimensions.width}
allowEditing={allowEditing}
focusOnHover={focusOnHover}
cancelPanDrag={cancelPanDrag}
onCreateEditEvent={onCreateEditEvent}
onModifyEditEvent={onModifyEditEvent}
Expand Down
11 changes: 6 additions & 5 deletions src/components/CanvasElementsRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { CanvasPrimitiveRenderer } from "./CanvasPrimitiveRenderer"
import { pcb_port, type AnyCircuitElement } from "circuit-json"
import { useMemo } from "react"
import { convertElementToPrimitives } from "../lib/convert-element-to-primitive"
import { Matrix } from "transformation-matrix"
import { GridConfig, Primitive } from "lib/types"
import type { Matrix } from "transformation-matrix"
import type { GridConfig, Primitive } from "lib/types"
import { MouseElementTracker } from "./MouseElementTracker"
import { DimensionOverlay } from "./DimensionOverlay"
import { ToolbarOverlay } from "./ToolbarOverlay"
import { ErrorOverlay } from "./ErrorOverlay"
import { EditPlacementOverlay } from "./EditPlacementOverlay"
import { EditEvent } from "lib/edit-events"
import type { EditEvent } from "lib/edit-events"
import { EditTraceHintOverlay } from "./EditTraceHintOverlay"
import { RatsNestOverlay } from "./RatsNestOverlay"
import { getFullConnectivityMapFromCircuitJson } from "circuit-json-to-connectivity-map"
Expand All @@ -23,7 +23,8 @@ export interface CanvasElementsRendererProps {
height?: number
grid?: GridConfig
allowEditing: boolean
cancelPanDrag: Function
focusOnHover: boolean
cancelPanDrag: () => void
onCreateEditEvent: (event: EditEvent) => void
onModifyEditEvent: (event: Partial<EditEvent>) => void
}
Expand Down Expand Up @@ -95,7 +96,7 @@ export const CanvasElementsRenderer = (props: CanvasElementsRendererProps) => {
onCreateEditEvent={props.onCreateEditEvent as any}
onModifyEditEvent={props.onModifyEditEvent as any}
>
<DimensionOverlay transform={transform!}>
<DimensionOverlay transform={transform!} focusOnHover={props.focusOnHover}>
<ToolbarOverlay elements={elements}>
<ErrorOverlay transform={transform} elements={elements}>
<RatsNestOverlay transform={transform} soup={elements}>
Expand Down
12 changes: 8 additions & 4 deletions src/components/DimensionOverlay.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { zIndexMap } from "lib/util/z-index-map"
import { useEffect, useRef, useState } from "react"
import { Matrix, applyToPoint, identity, inverse } from "transformation-matrix"
import type { Matrix } from "transformation-matrix"
import { applyToPoint, identity, inverse } from "transformation-matrix"

interface Props {
transform?: Matrix
children: any
focusOnHover?: boolean
}

export const DimensionOverlay = ({ children, transform }: Props) => {
export const DimensionOverlay = ({ children, transform, focusOnHover = false }: Props) => {
if (!transform) transform = identity()
const [dimensionToolVisible, setDimensionToolVisible] = useState(false)
const [dimensionToolStretching, setDimensionToolStretching] = useState(false)
Expand Down Expand Up @@ -83,10 +85,11 @@ export const DimensionOverlay = ({ children, transform }: Props) => {
return (
<div
ref={containerRef}
// biome-ignore lint/a11y/noNoninteractiveTabindex: <explanation>
tabIndex={0}
style={{ position: "relative" }}
onMouseEnter={() => {
if (containerRef.current) {
if (focusOnHover && containerRef.current) {
containerRef.current.focus()
}
}}
Expand Down Expand Up @@ -162,6 +165,7 @@ export const DimensionOverlay = ({ children, transform }: Props) => {
{Math.abs(dStart.y - dEnd.y).toFixed(2)}
</div>
</div>
{/* biome-ignore lint/a11y/noSvgWithoutTitle: <explanation> */}
<svg
style={{
position: "absolute",
Expand Down Expand Up @@ -232,7 +236,7 @@ export const DimensionOverlay = ({ children, transform }: Props) => {
{dEnd.x.toFixed(2)},{dEnd.y.toFixed(2)})<br />
dist:{" "}
{Math.sqrt(
Math.pow(dEnd.x - dStart.x, 2) + Math.pow(dEnd.y - dStart.y, 2),
((dEnd.x - dStart.x) ** 2) + ((dEnd.y - dStart.y) ** 2)
).toFixed(2)}
</div>
</>
Expand Down
16 changes: 8 additions & 8 deletions src/components/MouseElementTracker.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { useState } from "react"
import { useMemo } from "react"
import { Matrix, applyToPoint, inverse } from "transformation-matrix"
import { Primitive } from "lib/types"
import React, { useState, useMemo } from "react"
import type { Matrix } from "transformation-matrix"
import { applyToPoint, inverse } from "transformation-matrix"
import type { Primitive } from "lib/types"
import { ElementOverlayBox } from "./ElementOverlayBox"
import { AnyCircuitElement } from "circuit-json"
import type { AnyCircuitElement } from "circuit-json"
import { ifSetsMatchExactly } from "lib/util/if-sets-match-exactly"
import { pointToSegmentDistance } from "@tscircuit/math-utils"

Expand Down Expand Up @@ -43,7 +43,7 @@ export const MouseElementTracker = ({

// FANCY: If 2+ highlighted primitives inhabit the same space, give
// them an incrementing same_space_index
let same_space_index = highlightedPrimitives.filter(
const same_space_index = highlightedPrimitives.filter(
(hp) =>
screenPos.x === hp.screen_x &&
screenPos.y === hp.screen_y &&
Expand Down Expand Up @@ -96,8 +96,8 @@ export const MouseElementTracker = ({
if (!("x" in primitive && "y" in primitive)) continue

// Handle different primitive types
let w = 0,
h = 0
let w = 0
let h = 0

if ("w" in primitive && "h" in primitive) {
w = primitive.w
Expand Down
95 changes: 95 additions & 0 deletions src/stories/hover-behavior.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import type { Meta, StoryObj } from "@storybook/react"
import { Circuit } from "@tscircuit/core"
import { PCBViewer } from "../PCBViewer"

const HoverBehaviorDemo: React.FC<{ focusOnHover?: boolean }> = ({
focusOnHover,
}) => {
const circuit = new Circuit()

circuit.add(
<board width="20mm" height="20mm">
<resistor
name="R0"
pcbX={-4}
pcbY={-2}
footprint="1210"
resistance="10kohm"
/>
<resistor
name="R1"
pcbX={-4}
pcbY={0}
footprint="1210"
resistance="10kohm"
/>
<resistor
name="R2"
pcbX={2}
pcbY={3}
footprint="0603"
resistance="10kohm"
/>
<resistor
name="R3"
pcbX={0}
pcbY={6}
footprint="0805"
resistance="10kohm"
/>
<trace path={[".R1 > .right", "net.Ground"]} />
<trace path={[".R0 > .right", "net.Ground"]} />
<trace path={["net.Ground", ".R2 > .left"]} />
<trace path={[".R3 > .left", ".R2 > .right"]} />
</board>,
)

const soup = circuit.getCircuitJson()

return (
<div style={{ height: "200vh", padding: "100px 0" }}>
<div style={{ backgroundColor: "black", margin: "300px 0" }}>
<PCBViewer soup={soup} focusOnHover={focusOnHover} />
</div>
</div>
)
}

// Story with hover focus disabled (default behavior)
export const HoverDisabled: Story = {
args: {
focusOnHover: false,
},
parameters: {
docs: {
description: {
story:
"Hover focus is disabled by default. Hovering over the PCB viewer will not cause the page to scroll or adjust focus position.",
},
},
},
}

// Story with hover focus enabled
export const HoverEnabled: Story = {
args: {
focusOnHover: true,
},
parameters: {
docs: {
description: {
story:
"Hover focus is enabled. Hovering over the PCB viewer will cause it to receive focus and may adjust the scroll position.",
},
},
},
}

const meta: Meta<typeof HoverBehaviorDemo> = {
title: "Hover Behavior",
component: HoverBehaviorDemo,
}

export default meta

type Story = StoryObj<typeof HoverBehaviorDemo>
Loading