Skip to content
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
45 changes: 42 additions & 3 deletions package/src/components/page-toolbar-css/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ type HoverInfo = {
elementPath: string;
rect: DOMRect | null;
reactComponents?: string | null;
innermostComponent?: string | null;
computedStylesObj?: Record<string, string>;
};

export type OutputDetailLevel = "compact" | "standard" | "detailed" | "forensic";
Expand All @@ -153,6 +155,8 @@ export type ToolbarSettings = {
markerClickBehavior: MarkerClickBehavior;
webhookUrl: string;
webhooksEnabled: boolean;
hoverShowComponent: boolean;
hoverShowStyles: boolean;
};

const DEFAULT_SETTINGS: ToolbarSettings = {
Expand All @@ -164,6 +168,8 @@ const DEFAULT_SETTINGS: ToolbarSettings = {
markerClickBehavior: "edit",
webhookUrl: "",
webhooksEnabled: true,
hoverShowComponent: false,
hoverShowStyles: false,
};

// Simple URL validation - checks for valid http(s) URL format
Expand Down Expand Up @@ -1860,19 +1866,33 @@ const [settings, setSettings] = useState<ToolbarSettings>(() => {
identifyElementWithReact(elementUnder, effectiveReactMode);
const rect = elementUnder.getBoundingClientRect();

// Extract innermost component for hover display
let innermostComponent: string | null = null;
if (reactComponents) {
const parts = reactComponents.split(" ");
innermostComponent = parts[parts.length - 1] || null;
}

// Compute styles on hover when setting is enabled
const hoverComputedStyles = settings.hoverShowStyles
? getDetailedComputedStyles(elementUnder)
: undefined;

setHoverInfo({
element: name,
elementName,
elementPath: path,
rect,
reactComponents,
innermostComponent,
computedStylesObj: hoverComputedStyles,
});
setHoverPosition({ x: e.clientX, y: e.clientY });
};

document.addEventListener("mousemove", handleMouseMove);
return () => document.removeEventListener("mousemove", handleMouseMove);
}, [isActive, pendingAnnotation, isDrawMode, isDesignMode, effectiveReactMode, drawStrokes]);
}, [isActive, pendingAnnotation, isDrawMode, isDesignMode, effectiveReactMode, drawStrokes, settings.hoverShowStyles, settings.hoverShowComponent]);

// Start editing an annotation (right-click or click on drawing stroke)
const startEditAnnotation = useCallback((annotation: Annotation) => {
Expand Down Expand Up @@ -4421,19 +4441,38 @@ const [settings, setSettings] = useState<ToolbarSettings>(() => {
Math.min(hoverPosition.x, window.innerWidth - 100),
),
top: Math.max(
hoverPosition.y - (hoverInfo.reactComponents ? 48 : 32),
hoverPosition.y - (
(settings.hoverShowStyles && hoverInfo.computedStylesObj && Object.keys(hoverInfo.computedStylesObj).length > 0)
? 80 + Object.keys(hoverInfo.computedStylesObj).length * 16
: hoverInfo.reactComponents ? 48 : 32
),
8,
),
}}
>
{hoverInfo.reactComponents && (
<div className={styles.hoverReactPath}>
{hoverInfo.reactComponents}
{settings.hoverShowComponent && hoverInfo.innermostComponent
? hoverInfo.innermostComponent
: hoverInfo.reactComponents}
</div>
)}
<div className={styles.hoverElementName}>
{hoverInfo.elementName}
</div>
{settings.hoverShowStyles && hoverInfo.computedStylesObj && Object.keys(hoverInfo.computedStylesObj).length > 0 && (
<div className={styles.hoverStyles}>
{Object.entries(hoverInfo.computedStylesObj).map(([key, value]) => (
<div key={key} className={styles.hoverStyleLine}>
<span className={styles.hoverStyleProp}>
{key.replace(/([A-Z])/g, "-$1").toLowerCase()}
</span>
{": "}
<span className={styles.hoverStyleVal}>{value}</span>
</div>
))}
</div>
)}
</div>
)}

Expand Down
18 changes: 18 additions & 0 deletions package/src/components/page-toolbar-css/settings-panel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,24 @@ export function SettingsPanel({
onSettingsChange({ blockInteractions: e.target.checked })
}
/>
<CheckboxField
className={styles.checkboxField}
label="Show component on hover"
checked={settings.hoverShowComponent}
onChange={(e) =>
onSettingsChange({ hoverShowComponent: e.target.checked })
}
tooltip="Show only the innermost React component name in the hover tooltip instead of the full tree"
/>
<CheckboxField
className={styles.checkboxField}
label="Show styles on hover"
checked={settings.hoverShowStyles}
onChange={(e) =>
onSettingsChange({ hoverShowStyles: e.target.checked })
}
tooltip="Show computed CSS styles in the hover tooltip"
/>
</div>

<div className={styles.divider} />
Expand Down
23 changes: 23 additions & 0 deletions package/src/components/page-toolbar-css/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,29 @@
text-overflow: ellipsis;
}

.hoverStyles {
margin-top: 0.25rem;
padding-top: 0.25rem;
border-top: 1px solid rgba(255, 255, 255, 0.15);
font-size: 0.5625rem;
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
line-height: 1.45;
}

.hoverStyleLine {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.hoverStyleProp {
color: rgba(255, 255, 255, 0.55);
}

.hoverStyleVal {
color: rgba(255, 255, 255, 0.9);
}

// =============================================================================
// Markers Layer
// =============================================================================
Expand Down