Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit322b5bf

Browse files
committed
feat: highlight elements matching selector on hover
1 parentee8eb53 commit322b5bf

File tree

9 files changed

+157
-57
lines changed

9 files changed

+157
-57
lines changed

‎entrypoints/content.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ export default defineContentScript({
5050
onDevtoolsMessage.removeInlineStyle((message)=>{
5151
returninspectApi.removeInlineStyleAction(message.data);
5252
});
53+
54+
onDevtoolsMessage.highlightSelector((message)=>{
55+
returninspectApi.highlightSelector(message.data);
56+
});
5357
},
5458
});
5559

‎playground/src/browser-context.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const evaluator: Evaluator = {
3131
}
3232
});
3333
},
34-
copy:(valueToCopy:string)=>{
34+
copy:async(valueToCopy:string)=>{
3535
navigator.clipboard.writeText(valueToCopy);
3636
},
3737
inspect:async()=>{
@@ -64,6 +64,9 @@ const contentScript: ContentScriptApi = {
6464
removeInlineStyle:async(message)=>{
6565
returninspectApi.removeInlineStyleAction(message);
6666
},
67+
highlightSelector:async(message)=>{
68+
returninspectApi.highlightSelector(message);
69+
},
6770
};
6871

6972
exportconstbrowserContext:DevtoolsContextValue={

‎playground/src/element-inspector.tsx

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React, { useEffect, useRef, useState } from "react";
44
import{css}from"../../styled-system/css";
55
import{ElementDetails,ElementDetailsData}from"./element-details";
66
import{getInspectedElement}from"./inspected";
7+
import{getHighlightsStyles}from"../../src/lib/get-highlights-styles";
78

89
exportconstElementInspector=({
910
onInspect,
@@ -46,7 +47,7 @@ export const ElementInspector = ({
4647
},
4748
});
4849

49-
setHighlightStyles(getHighlights(element));
50+
setHighlightStyles(getHighlightsStyles(element)asReact.CSSProperties[]);
5051

5152
clean();
5253
};
@@ -143,56 +144,3 @@ const tooltipStyles = css({
143144
flexDirection:"column",
144145
gap:"2px",
145146
});
146-
147-
constgetHighlights=(element:HTMLElement)=>{
148-
constrect=element.getBoundingClientRect();
149-
constcomputedStyle=window.getComputedStyle(element);
150-
151-
constmargin={
152-
top:parseInt(computedStyle.marginTop,10),
153-
right:parseInt(computedStyle.marginRight,10),
154-
bottom:parseInt(computedStyle.marginBottom,10),
155-
left:parseInt(computedStyle.marginLeft,10),
156-
};
157-
constpadding={
158-
top:parseInt(computedStyle.paddingTop,10),
159-
right:parseInt(computedStyle.paddingRight,10),
160-
bottom:parseInt(computedStyle.paddingBottom,10),
161-
left:parseInt(computedStyle.paddingLeft,10),
162-
};
163-
164-
return[
165-
// Margin overlay
166-
{
167-
position:"absolute",
168-
top:rect.top+window.scrollY-margin.top,
169-
left:rect.left+window.scrollX-margin.left,
170-
width:rect.width+margin.left+margin.right,
171-
height:rect.height+margin.top+margin.bottom,
172-
backgroundColor:"rgba(246, 178, 107, 0.65)",// orange
173-
zIndex:9990,
174-
},
175-
// Padding overlay
176-
{
177-
position:"absolute",
178-
top:rect.top+window.scrollY,
179-
left:rect.left+window.scrollX,
180-
width:rect.width,
181-
height:rect.height,
182-
boxShadow:`inset 0px 0px 0px${padding.top}px rgb(94 151 68 / 65%)`,// green
183-
zIndex:9991,
184-
},
185-
// Content area indicator
186-
{
187-
position:"absolute",
188-
top:rect.top+window.scrollY+padding.top,
189-
left:rect.left+window.scrollX+padding.left,
190-
width:rect.width-padding.left-padding.right,
191-
height:rect.height-padding.top-padding.bottom,
192-
backgroundColor:"color-mix(in srgb, rgb(0, 144, 255) 100%, white 100%)",
193-
zIndex:9992,
194-
opacity:0.62,
195-
mixBlendMode:"color",
196-
},
197-
]asReact.CSSProperties[];
198-
};

‎playground/src/playground.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,16 @@ function Playground() {
3131
p:"4",
3232
})}
3333
>
34-
Atomic CSS Devtools [data-inspected-element]
34+
Atomic CSS Devtools
35+
</div>
36+
<div
37+
className={css({
38+
fontSize:"4xl",
39+
p:"4",
40+
color:"blue.400",
41+
})}
42+
>
43+
[data-inspected-element]
3544
</div>
3645
</HStack>
3746
<HStack>

‎src/declaration.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,27 @@ export const Declaration = (props: DeclarationProps) => {
338338
onClick={async()=>{
339339
awaitevaluator.copy(prettySelector);
340340
}}
341+
onMouseOver={()=>{
342+
contentScript.highlightSelector({
343+
selectors:
344+
rule.selector===symbols.inlineStyleSelector
345+
?inspected.elementSelectors
346+
:[rule.selector],
347+
});
348+
}}
349+
onMouseOut={(e)=>{
350+
// Skip if the mouse is hovering same selector
351+
if(
352+
e.targetinstanceofHTMLElement&&
353+
e.relatedTargetinstanceofHTMLElement&&
354+
e.target.innerText===e.relatedTarget.innerText
355+
){
356+
return;
357+
}
358+
359+
// Clear highlights
360+
contentScript.highlightSelector({selectors:[]});
361+
}}
341362
>
342363
<HighlightMatchhighlight={filter}>
343364
{prettySelector}

‎src/devtools-context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export interface Evaluator {
1616
fn:T,
1717
...args:WithoutFirst<T>
1818
)=>Promise<ReturnType<T>>;
19-
copy:(valueToCopy:string)=>void;
19+
copy:(valueToCopy:string)=>Promise<void>;
2020
inspect:()=>Promise<InspectResult|null|undefined>;
2121
onSelectionChanged:(
2222
cb:(element:InspectResult|null)=>void

‎src/devtools-messages.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ export interface ContentScriptEvents {
3030
RemoveInlineStyle&Pick<UpdateStyleRuleMessage,"selectors"|"prop">,
3131
InlineStyleReturn
3232
>;
33+
highlightSelector:DevtoolsMessage<
34+
{selectors:string[]},
35+
ReturnType<InspectAPI["highlightSelector"]>
36+
>;
3337
}
3438

3539
exporttypeContentScriptApi={

‎src/inspect-api.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import {
1414
MatchedMediaRule,
1515
MatchedLayerBlockRule,
1616
}from"./devtools-types";
17+
import{getHighlightsStyles}from"./lib/get-highlights-styles";
18+
import{dashCase}from"@pandacss/shared";
1719

1820
exportclassInspectAPI{
1921
traverseSelectors(selectors:string[]):HTMLElement|null{
@@ -513,6 +515,62 @@ export class InspectAPI {
513515
returnsplit.filter(Boolean).join(";")+";";
514516
}
515517

518+
privateprevHighlightedSelector:string|null=null;
519+
520+
highlightSelector(params:{selectors:string[]}){
521+
const{ selectors}=params;
522+
523+
// Remove any existing highlight
524+
document.querySelectorAll("[data-selector-highlighted]").forEach((el)=>{
525+
if(elinstanceofHTMLElement){
526+
deleteel.dataset.selectorHighlighted;
527+
}
528+
});
529+
530+
letcontainer=document.querySelector(
531+
"[data-selector-highlighted-container]"
532+
);
533+
if(!container){
534+
container=document.createElement("div")asHTMLElement;
535+
container.setAttribute("data-selector-highlighted-container","");
536+
container.setAttribute("style","pointer-events: none;");
537+
document.body.appendChild(container);
538+
}
539+
540+
// Explicitly clear container if no selectors were passed
541+
if(!selectors.length){
542+
container.innerHTML="";
543+
this.prevHighlightedSelector=null;
544+
return;
545+
}
546+
547+
// Add highlight to the elements matching the selectors
548+
// Ignore selectors that contain `*` because they are too broad
549+
constselector=selectors.filter((s)=>!s.includes("*")).join(",");
550+
if(!selector)return;
551+
if(this.prevHighlightedSelector===selector)return;
552+
553+
// Clear container children if no selectors are left
554+
container.innerHTML="";
555+
556+
this.prevHighlightedSelector=selector;
557+
558+
document.querySelectorAll(selector).forEach((el)=>{
559+
if(elinstanceofHTMLElement){
560+
el.dataset.selectorHighlighted="";
561+
562+
consthighlights=getHighlightsStyles(el);
563+
highlights.forEach((styles)=>{
564+
consthighlight=document.createElement("div")asHTMLElement;
565+
highlight.style.cssText=Object.entries(styles)
566+
.map(([prop,value])=>`${dashCase(prop)}:${value}`)
567+
.join(";");
568+
container.appendChild(highlight);
569+
});
570+
}
571+
});
572+
}
573+
516574
privatecreateSerializer(){
517575
// https://developer.mozilla.org/en-US/docs/Web/API/CSSRule/type
518576
constcache=newWeakMap<CSSRule,MatchedRule>();

‎src/lib/get-highlights-styles.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
exportconstgetHighlightsStyles=(element:HTMLElement)=>{
2+
constrect=element.getBoundingClientRect();
3+
constcomputedStyle=window.getComputedStyle(element);
4+
5+
constmargin={
6+
top:parseInt(computedStyle.marginTop,10),
7+
right:parseInt(computedStyle.marginRight,10),
8+
bottom:parseInt(computedStyle.marginBottom,10),
9+
left:parseInt(computedStyle.marginLeft,10),
10+
};
11+
constpadding={
12+
top:parseInt(computedStyle.paddingTop,10),
13+
right:parseInt(computedStyle.paddingRight,10),
14+
bottom:parseInt(computedStyle.paddingBottom,10),
15+
left:parseInt(computedStyle.paddingLeft,10),
16+
};
17+
18+
return[
19+
// Margin overlay
20+
{
21+
position:"absolute",
22+
top:rect.top+window.scrollY-margin.top+"px",
23+
left:rect.left+window.scrollX-margin.left+"px",
24+
width:rect.width+margin.left+margin.right+"px",
25+
height:rect.height+margin.top+margin.bottom+"px",
26+
backgroundColor:"rgba(246, 178, 107, 0.65)",// orange
27+
zIndex:"9990",
28+
},
29+
// Padding overlay
30+
{
31+
position:"absolute",
32+
top:rect.top+window.scrollY+"px",
33+
left:rect.left+window.scrollX+"px",
34+
width:rect.width+"px",
35+
height:rect.height+"px",
36+
boxShadow:`inset 0px 0px 0px${padding.top}px rgb(94 151 68 / 65%)`,// green
37+
zIndex:"9991",
38+
},
39+
// Content area indicator
40+
{
41+
position:"absolute",
42+
top:rect.top+window.scrollY+padding.top+"px",
43+
left:rect.left+window.scrollX+padding.left+"px",
44+
width:rect.width-padding.left-padding.right+"px",
45+
height:rect.height-padding.top-padding.bottom+"px",
46+
// backgroundColor: "color-mix(in srgb, rgb(0, 144, 255) 100%, white 100%)",
47+
backgroundColor:"rgb(72 175 255)",
48+
zIndex:"9992",
49+
opacity:"0.62",
50+
mixBlendMode:"color",
51+
},
52+
]asArray<Partial<HTMLElement["style"]>>;
53+
};

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp