From b9e3e132337d6aa4f194ea070c0b82f46da90c77 Mon Sep 17 00:00:00 2001 From: Kom Senapati Date: Sat, 18 Jan 2025 07:06:48 +0000 Subject: [PATCH 1/3] feat: disable "mouse hover focuses PCB viewer" by default, enable with prop focusOnHover - The default behavior for mouse hover focusing the PCB viewer has been disabled. - Added a new `focusOnHover` prop to allow enabling this feature if required. --- src/PCBViewer.tsx | 3 +++ src/components/CanvasElementsRenderer.tsx | 2 ++ src/components/MouseElementTracker.tsx | 10 ++++++++++ 3 files changed, 15 insertions(+) diff --git a/src/PCBViewer.tsx b/src/PCBViewer.tsx index d9cb64a..80ef800 100644 --- a/src/PCBViewer.tsx +++ b/src/PCBViewer.tsx @@ -23,6 +23,7 @@ type Props = { editEvents?: EditEvent[] initialState?: Partial onEditEventsChanged?: (editEvents: EditEvent[]) => void + focusOnHover?: boolean } export const PCBViewer = ({ @@ -34,6 +35,7 @@ export const PCBViewer = ({ allowEditing = true, editEvents: editEventsProp, onEditEventsChanged, + focusOnHover = false, }: Props) => { circuitJson ??= soup const { @@ -123,6 +125,7 @@ export const PCBViewer = ({ height={height} width={refDimensions.width} allowEditing={allowEditing} + focusOnHover={focusOnHover} cancelPanDrag={cancelPanDrag} onCreateEditEvent={onCreateEditEvent} onModifyEditEvent={onModifyEditEvent} diff --git a/src/components/CanvasElementsRenderer.tsx b/src/components/CanvasElementsRenderer.tsx index 5c881b3..3fd493d 100644 --- a/src/components/CanvasElementsRenderer.tsx +++ b/src/components/CanvasElementsRenderer.tsx @@ -23,6 +23,7 @@ export interface CanvasElementsRendererProps { height?: number grid?: GridConfig allowEditing: boolean + focusOnHover: boolean cancelPanDrag: Function onCreateEditEvent: (event: EditEvent) => void onModifyEditEvent: (event: Partial) => void @@ -50,6 +51,7 @@ export const CanvasElementsRenderer = (props: CanvasElementsRendererProps) => { elements={elements} transform={transform} primitives={primitivesWithoutInteractionMetadata} + focusOnHover={props.focusOnHover} onMouseHoverOverPrimitives={(primitivesHoveredOver) => { const primitiveIdsInMousedOverNet: string[] = [] for (const primitive of primitivesHoveredOver) { diff --git a/src/components/MouseElementTracker.tsx b/src/components/MouseElementTracker.tsx index 176afac..eea07a9 100644 --- a/src/components/MouseElementTracker.tsx +++ b/src/components/MouseElementTracker.tsx @@ -12,12 +12,14 @@ export const MouseElementTracker = ({ children, transform, primitives, + focusOnHover, onMouseHoverOverPrimitives, }: { elements: AnyCircuitElement[] children: any transform?: Matrix primitives: Primitive[] + focusOnHover: boolean onMouseHoverOverPrimitives: (primitivesHoveredOver: Primitive[]) => void }) => { const [mousedPrimitives, setMousedPrimitives] = useState([]) @@ -117,6 +119,14 @@ export const MouseElementTracker = ({ } } + if (!focusOnHover) { + if (mousedPrimitives.length > 0) { + setMousedPrimitives([]) + onMouseHoverOverPrimitives([]) + } + return + } + if ( ifSetsMatchExactly( new Set(newMousedPrimitives.map((p) => p._pcb_drawing_object_id)), From 5ce76cd8d64403a95d555fa16e465013f82e1908 Mon Sep 17 00:00:00 2001 From: Kom Senapati Date: Sun, 19 Jan 2025 07:36:57 +0000 Subject: [PATCH 2/3] chore: story for hover behaviour --- src/stories/hover-behavior.stories.tsx | 93 ++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/stories/hover-behavior.stories.tsx diff --git a/src/stories/hover-behavior.stories.tsx b/src/stories/hover-behavior.stories.tsx new file mode 100644 index 0000000..dccb0be --- /dev/null +++ b/src/stories/hover-behavior.stories.tsx @@ -0,0 +1,93 @@ +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( + + + + + + .right", "net.Ground"]} /> + .right", "net.Ground"]} /> + .left"]} /> + .left", ".R2 > .right"]} /> + , + ) + + const soup = circuit.getCircuitJson() + + return ( +
+ +
+ ) +} + +// 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 components and traces will not highlight them.", + }, + }, + }, +} + +// Story with hover focus enabled +export const HoverEnabled: Story = { + args: { + focusOnHover: true, + }, + parameters: { + docs: { + description: { + story: + "Hover focus is enabled. Hovering over components and traces will highlight them and their connected elements.", + }, + }, + }, +} + +const meta: Meta = { + title: "Hover Behavior", + component: HoverBehaviorDemo, +} + +export default meta + +type Story = StoryObj From 424d564ea29c995cdaff91bb576b169ee4229793 Mon Sep 17 00:00:00 2001 From: Kom Senapati Date: Wed, 22 Jan 2025 06:53:48 +0000 Subject: [PATCH 3/3] fix: adjust scrollview instead of toggling traces --- src/components/CanvasElementsRenderer.tsx | 11 +++++----- src/components/DimensionOverlay.tsx | 12 +++++++---- src/components/MouseElementTracker.tsx | 26 +++++++---------------- src/stories/hover-behavior.stories.tsx | 10 +++++---- 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/components/CanvasElementsRenderer.tsx b/src/components/CanvasElementsRenderer.tsx index 3fd493d..5a62138 100644 --- a/src/components/CanvasElementsRenderer.tsx +++ b/src/components/CanvasElementsRenderer.tsx @@ -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" @@ -24,7 +24,7 @@ export interface CanvasElementsRendererProps { grid?: GridConfig allowEditing: boolean focusOnHover: boolean - cancelPanDrag: Function + cancelPanDrag: () => void onCreateEditEvent: (event: EditEvent) => void onModifyEditEvent: (event: Partial) => void } @@ -51,7 +51,6 @@ export const CanvasElementsRenderer = (props: CanvasElementsRendererProps) => { elements={elements} transform={transform} primitives={primitivesWithoutInteractionMetadata} - focusOnHover={props.focusOnHover} onMouseHoverOverPrimitives={(primitivesHoveredOver) => { const primitiveIdsInMousedOverNet: string[] = [] for (const primitive of primitivesHoveredOver) { @@ -97,7 +96,7 @@ export const CanvasElementsRenderer = (props: CanvasElementsRendererProps) => { onCreateEditEvent={props.onCreateEditEvent as any} onModifyEditEvent={props.onModifyEditEvent as any} > - + diff --git a/src/components/DimensionOverlay.tsx b/src/components/DimensionOverlay.tsx index 7a8acf2..22225ac 100644 --- a/src/components/DimensionOverlay.tsx +++ b/src/components/DimensionOverlay.tsx @@ -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) @@ -83,10 +85,11 @@ export const DimensionOverlay = ({ children, transform }: Props) => { return (
tabIndex={0} style={{ position: "relative" }} onMouseEnter={() => { - if (containerRef.current) { + if (focusOnHover && containerRef.current) { containerRef.current.focus() } }} @@ -162,6 +165,7 @@ export const DimensionOverlay = ({ children, transform }: Props) => { {Math.abs(dStart.y - dEnd.y).toFixed(2)}
+ {/* biome-ignore lint/a11y/noSvgWithoutTitle: */} { {dEnd.x.toFixed(2)},{dEnd.y.toFixed(2)})
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)} diff --git a/src/components/MouseElementTracker.tsx b/src/components/MouseElementTracker.tsx index eea07a9..c354068 100644 --- a/src/components/MouseElementTracker.tsx +++ b/src/components/MouseElementTracker.tsx @@ -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" @@ -12,14 +12,12 @@ export const MouseElementTracker = ({ children, transform, primitives, - focusOnHover, onMouseHoverOverPrimitives, }: { elements: AnyCircuitElement[] children: any transform?: Matrix primitives: Primitive[] - focusOnHover: boolean onMouseHoverOverPrimitives: (primitivesHoveredOver: Primitive[]) => void }) => { const [mousedPrimitives, setMousedPrimitives] = useState([]) @@ -45,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 && @@ -98,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 @@ -119,14 +117,6 @@ export const MouseElementTracker = ({ } } - if (!focusOnHover) { - if (mousedPrimitives.length > 0) { - setMousedPrimitives([]) - onMouseHoverOverPrimitives([]) - } - return - } - if ( ifSetsMatchExactly( new Set(newMousedPrimitives.map((p) => p._pcb_drawing_object_id)), diff --git a/src/stories/hover-behavior.stories.tsx b/src/stories/hover-behavior.stories.tsx index dccb0be..852873b 100644 --- a/src/stories/hover-behavior.stories.tsx +++ b/src/stories/hover-behavior.stories.tsx @@ -47,8 +47,10 @@ const HoverBehaviorDemo: React.FC<{ focusOnHover?: boolean }> = ({ const soup = circuit.getCircuitJson() return ( -
- +
+
+ +
) } @@ -62,7 +64,7 @@ export const HoverDisabled: Story = { docs: { description: { story: - "Hover focus is disabled by default. Hovering over components and traces will not highlight them.", + "Hover focus is disabled by default. Hovering over the PCB viewer will not cause the page to scroll or adjust focus position.", }, }, }, @@ -77,7 +79,7 @@ export const HoverEnabled: Story = { docs: { description: { story: - "Hover focus is enabled. Hovering over components and traces will highlight them and their connected elements.", + "Hover focus is enabled. Hovering over the PCB viewer will cause it to receive focus and may adjust the scroll position.", }, }, },