Skip to content

Commit

Permalink
Fix auto select in InspectDataMenu when opened above cursor (#691)
Browse files Browse the repository at this point in the history
This PR addresses an issue where the inspector context menu
automatically selects and closes upon appearing above the cursor. The
problem was caused by the menu opening upon mouseUp immediately after a
mouseDown event.

The solution ensures the menu displays adjacent to the cursor with an
offset by introducing a `span` that positions the `Trigger` component at
the mouse location, ensuring the menu opens next to the `Trigger`.

Additionally, this PR:
- limits the number of inspect items displayed in `InspectDataMenu` to 5
using `MAX_INSPECT_ITEMS`
- adds a "Show all" button to reveal all items
- adds ellipsis truncation for long filenames in `InspectDataMenu`
- adjusts menu alignment based on cursor position, displaying to the
right if the cursor is on the left side of the screen and to the left if
on the right


Fixes #687 

### How Has This Been Tested: 
- Tested by right-clicking near the screen's bottom, ensuring the menu
opens above the cursor and doesn't auto-select any items.

After:
<img width="239" alt="Screenshot 2024-11-04 at 20 39 32"
src="https://github.com/user-attachments/assets/ec95ac31-0204-4d65-91c7-c40d297421d9">
<img width="386" alt="Screenshot 2024-11-05 at 18 33 04"
src="https://github.com/user-attachments/assets/423ff8eb-1416-4ee2-a2ea-824be2ff7faf">


https://github.com/user-attachments/assets/b09a6fdb-23a6-4ecd-b707-980f7074a652
  • Loading branch information
p-malecki authored Nov 6, 2024
1 parent 0b52a57 commit ece3b3d
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,31 @@
color: var(--swm-disabled-text);
pointer-events: none;
}

.inspect-data-menu-item[data-highlighted] {
background-color: var(--swm-dropdown-item-highlighted);
color: var(--swm-default-text);
overflow-wrap: anywhere;
}

.inspect-data-menu-item .right-slot {
color: var(--swm-device-select-rich-item-subtitle);
font-size: 90%;
margin-left: auto;
overflow-wrap: anywhere;
padding-left: 10px;
max-width: 150px;
display: flex;
min-width: 0;
align-items: center;
}
.inspect-data-menu-item .right-slot .filename {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-grow: 1;
}

.inspect-data-menu-item.show-all {
height: 15px;
min-height: 0;
padding: 3px 6px;
justify-content: center;
flex-wrap: nowrap;
}
118 changes: 85 additions & 33 deletions packages/vscode-extension/src/webview/components/InspectDataMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,43 @@
import React, { useState } from "react";
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import { Frame, InspectDataStackItem } from "../../common/Project";
import { DeviceProperties } from "../utilities/consts";
import "./InspectDataMenu.css";

type OnSelectedCallback = (item: InspectDataStackItem) => void;

const MAX_INSPECT_ITEMS = 5;

interface InspectItemProps {
item: InspectDataStackItem;
onSelected: (item: InspectDataStackItem) => void;
onHover: (item: InspectDataStackItem) => void;
}

const InspectItem = React.forwardRef<HTMLDivElement, InspectItemProps>(
({ item, onSelected, onHover }, forwardedRef) => {
const fullFileName = item.source.fileName.split("/").pop() ?? "";
const lastDotIndex = fullFileName.lastIndexOf(".");
const fileName = fullFileName.substring(0, lastDotIndex);
const fileExtension = fullFileName.substring(lastDotIndex);

return (
<DropdownMenu.Item
className="inspect-data-menu-item"
key={item.source.fileName + item.source.line0Based}
onSelect={() => onSelected(item)}
onMouseEnter={() => onHover(item)}
ref={forwardedRef}>
<code>{`<${item.componentName}>`}</code>
<div className="right-slot">
<span className="filename">{fileName}</span>
<span>{`${fileExtension}:${item.source.line0Based + 1}`}</span>
</div>
</DropdownMenu.Item>
);
}
);

type InspectDataMenuProps = {
inspectLocation: { x: number; y: number };
inspectStack: InspectDataStackItem[];
Expand All @@ -24,6 +57,8 @@ export function InspectDataMenu({
onHover,
onCancel,
}: InspectDataMenuProps) {
const [shouldShowAll, setShouldShowAll] = useState(false);

const displayDimensionsText = (() => {
if (device && frame) {
const topComponentWidth = parseFloat((frame.width * device.screenWidth).toFixed(2));
Expand All @@ -37,40 +72,57 @@ export function InspectDataMenu({
})();

const filteredData = inspectStack.filter((item) => !item.hide);
const inspectItems =
shouldShowAll || filteredData.length === MAX_INSPECT_ITEMS + 1
? filteredData
: filteredData.slice(0, MAX_INSPECT_ITEMS);
const inspectMenuAlign = inspectLocation.x <= window.innerWidth / 2 ? "start" : "end";
const isOverMaxItems = filteredData.length > MAX_INSPECT_ITEMS + 1;

return (
<div style={{ left: inspectLocation.x, top: inspectLocation.y, position: "absolute" }}>
<DropdownMenu.Root
defaultOpen={true}
open={true}
onOpenChange={(open) => {
if (!open) {
onCancel();
}
}}>
<DropdownMenu.Trigger />
<DropdownMenu.Portal>
<DropdownMenu.Content className="inspect-data-menu-content">
<DropdownMenu.Label className="inspect-data-menu-label">
{displayDimensionsText}
</DropdownMenu.Label>
{filteredData.map((item, index) => {
// extract file name from path:
const fileName = item.source.fileName.split("/").pop();
return (
<DropdownMenu.Item
className="inspect-data-menu-item"
key={index}
onSelect={() => onSelected(item)}
onMouseEnter={() => onHover(item)}>
<code>{`<${item.componentName}>`}</code>
<div className="right-slot">{`${fileName}:${item.source.line0Based + 1}`}</div>
</DropdownMenu.Item>
);
})}
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
</div>
<DropdownMenu.Root
defaultOpen={true}
open={true}
onOpenChange={(open) => {
if (!open) {
onCancel();
}
}}>
<DropdownMenu.Trigger asChild>
<span
style={{
position: "absolute",
left: inspectLocation.x,
top: inspectLocation.y,
opacity: 0,
}}
/>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
className="inspect-data-menu-content"
sideOffset={5}
align={inspectMenuAlign}
collisionPadding={5}>
<DropdownMenu.Label className="inspect-data-menu-label">
{displayDimensionsText}
</DropdownMenu.Label>
{inspectItems.map((item) => (
<InspectItem item={item} onSelected={onSelected} onHover={onHover} />
))}
{isOverMaxItems && !shouldShowAll && (
<DropdownMenu.Item
className="inspect-data-menu-item show-all"
key={"show-all"}
onSelect={(e) => {
setShouldShowAll(true);
e.preventDefault(); // prevents the dropdown from closing
}}>
<DropdownMenu.Label className="inspect-data-menu-label">Show all</DropdownMenu.Label>
</DropdownMenu.Item>
)}
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
}

0 comments on commit ece3b3d

Please sign in to comment.