@react-native/debugger-frontend
Version:
Debugger frontend for React Native based on Chrome DevTools
148 lines (138 loc) • 42.4 kB
JavaScript
import*as e from"../../core/common/common.js";import*as t from"../../core/sdk/sdk.js";import*as i from"../../core/i18n/i18n.js";import*as o from"../../core/root/root.js";import*as s from"../../ui/legacy/components/color_picker/color_picker.js";import"../../ui/components/buttons/buttons.js";import*as n from"../../ui/legacy/legacy.js";import*as r from"../../core/platform/platform.js";import*as a from"../../models/text_utils/text_utils.js";import*as l from"../../ui/components/icon_button/icon_button.js";import*as d from"../../ui/legacy/components/data_grid/data_grid.js";import*as c from"../../ui/legacy/components/utils/utils.js";import*as h from"../../ui/visual_logging/visual_logging.js";import*as u from"./components/components.js";import*as p from"../../core/host/host.js";class v extends e.ObjectWrapper.ObjectWrapper{currentUrl;constructor(){super(),this.currentUrl=t.TargetManager.TargetManager.instance().inspectedURL(),t.TargetManager.TargetManager.instance().addEventListener("InspectedURLChanged",this.#e,this)}#e(){this.currentUrl!==t.TargetManager.TargetManager.instance().inspectedURL()&&(this.currentUrl=t.TargetManager.TargetManager.instance().inspectedURL(),this.dispatchEventToListeners("Reset"))}}var m=Object.freeze({__proto__:null,OverviewController:v});const g={topAppliedToAStatically:"`Top` applied to a statically positioned element",leftAppliedToAStatically:"`Left` applied to a statically positioned element",rightAppliedToAStatically:"`Right` applied to a statically positioned element",bottomAppliedToAStatically:"`Bottom` applied to a statically positioned element",widthAppliedToAnInlineElement:"`Width` applied to an inline element",heightAppliedToAnInlineElement:"`Height` applied to an inline element",verticalAlignmentAppliedTo:"Vertical alignment applied to element which is neither `inline` nor `table-cell`"},w=i.i18n.registerUIStrings("panels/css_overview/CSSOverviewUnusedDeclarations.ts",g),f=i.i18n.getLocalizedString.bind(void 0,w);class b{static add(e,t,i){const o=e.get(t)||[];o.push(i),e.set(t,o)}static checkForUnusedPositionValues(e,t,i,o,s,n,r,a){if("static"===i[o]){if("auto"!==i[s]){const o=f(g.topAppliedToAStatically);this.add(e,o,{declaration:`top: ${i[s]}`,nodeId:t})}if("auto"!==i[n]){const o=f(g.leftAppliedToAStatically);this.add(e,o,{declaration:`left: ${i[n]}`,nodeId:t})}if("auto"!==i[r]){const o=f(g.rightAppliedToAStatically);this.add(e,o,{declaration:`right: ${i[r]}`,nodeId:t})}if("auto"!==i[a]){const o=f(g.bottomAppliedToAStatically);this.add(e,o,{declaration:`bottom: ${i[a]}`,nodeId:t})}}}static checkForUnusedWidthAndHeightValues(e,t,i,o,s,n){if("inline"===i[o]){if("auto"!==i[s]){const o=f(g.widthAppliedToAnInlineElement);this.add(e,o,{declaration:`width: ${i[s]}`,nodeId:t})}if("auto"!==i[n]){const o=f(g.heightAppliedToAnInlineElement);this.add(e,o,{declaration:`height: ${i[n]}`,nodeId:t})}}}static checkForInvalidVerticalAlignment(e,t,i,o,s){if(i[o]&&!i[o].startsWith("inline")&&!i[o].startsWith("table")&&"baseline"!==i[s]){const o=f(g.verticalAlignmentAppliedTo);this.add(e,o,{declaration:`vertical-align: ${i[s]}`,nodeId:t})}}}var S=Object.freeze({__proto__:null,CSSOverviewUnusedDeclarations:b});class C extends t.SDKModel.SDKModel{#t;#i;#o;#s;constructor(e){super(e),this.#t=e.runtimeAgent(),this.#i=e.cssAgent(),this.#o=e.domsnapshotAgent(),this.#s=e.overlayAgent()}highlightNode(t){const i={contentColor:e.Color.PageHighlight.Content.toProtocolRGBA(),showInfo:!0,contrastAlgorithm:o.Runtime.experiments.isEnabled("apca")?"apca":"aa"};this.#s.invoke_hideHighlight(),this.#s.invoke_highlightNode({backendNodeId:t,highlightConfig:i})}async getNodeStyleStats(){const t=new Map,i=new Map,n=new Map,r=new Map,a=new Map,l=new Map,d=new Map,c=t=>t instanceof e.Color.Legacy?t.hasAlpha()?t.asString("hexa"):t.asString("hex"):t.asString(),h=(t,i,o)=>{if(-1===t)return;const s=w[t];if(!s)return;const n=e.Color.parse(s);if(!n||0===n.asLegacyColor().rgba()[3])return;const r=c(n);if(!r)return;const a=o.get(r)||new Set;return a.add(i),o.set(r,a),n},u=e=>new Set(["altglyph","circle","ellipse","path","polygon","polyline","rect","svg","text","textpath","tref","tspan"]).has(e.toLowerCase()),p=e=>new Set(["iframe","video","embed","img"]).has(e.toLowerCase()),v=(e,t)=>new Set(["tr","td","thead","tbody"]).has(e.toLowerCase())&&t.startsWith("table");let m=0;const{documents:g,strings:w}=await this.#o.invoke_captureSnapshot({computedStyles:["background-color","color","fill","border-top-width","border-top-color","border-bottom-width","border-bottom-color","border-left-width","border-left-color","border-right-width","border-right-color","font-family","font-size","font-weight","line-height","position","top","right","bottom","left","display","width","height","vertical-align"],includeTextColorOpacities:!0,includeBlendedBackgroundColors:!0});for(const{nodes:f,layout:S}of g){m+=S.nodeIndex.length;for(let m=0;m<S.styles.length;m++){const g=S.styles[m],C=S.nodeIndex[m];if(!f.backendNodeId||!f.nodeName)continue;const y=f.backendNodeId[C],x=f.nodeName[C],[k,$,I,T,M,A,E,L,F,O,R,V,P,N,W,D,z,_,B,U,j,H,G,q]=g;h(k,y,t);const Q=h($,y,i);if(u(w[x])&&h(I,y,r),"0px"!==w[T]&&h(M,y,a),"0px"!==w[A]&&h(E,y,a),"0px"!==w[L]&&h(F,y,a),"0px"!==w[O]&&h(R,y,a),V&&-1!==V){const e=w[V],t=l.get(e)||new Map,i="font-size",o="font-weight",s="line-height",n=t.get(i)||new Map,r=t.get(o)||new Map,a=t.get(s)||new Map;if(-1!==P){const e=w[P],t=n.get(e)||[];t.push(y),n.set(e,t)}if(-1!==N){const e=w[N],t=r.get(e)||[];t.push(y),r.set(e,t)}if(-1!==W){const e=w[W],t=a.get(e)||[];t.push(y),a.set(e,t)}t.set(i,n),t.set(o,r),t.set(s,a),l.set(e,t)}const K=Q&&S.blendedBackgroundColors&&-1!==S.blendedBackgroundColors[m]?e.Color.parse(w[S.blendedBackgroundColors[m]]):null;if(Q&&K){const e=new s.ContrastInfo.ContrastInfo({backgroundColors:[K.asString("hexa")],computedFontSize:-1!==P?w[P]:"",computedFontWeight:-1!==N?w[N]:""}),t=Q.asLegacyColor().blendWithAlpha(S.textColorOpacities?S.textColorOpacities[m]:1);e.setColor(t);const i=`${c(t)}_${c(K.asLegacyColor())}`;if(o.Runtime.experiments.isEnabled("apca")){const o=e.contrastRatioAPCA(),s=e.contrastRatioAPCAThreshold();if(!(!(!o||!s)&&Math.abs(o)>=s)&&o){const e={nodeId:y,contrastRatio:o,textColor:t,backgroundColor:K,thresholdsViolated:{aa:!1,aaa:!1,apca:!0}};n.has(i)?n.get(i).push(e):n.set(i,[e])}}else{const o=e.contrastRatioThreshold("aa")||0,s=e.contrastRatioThreshold("aaa")||0,r=e.contrastRatio()||0;if(o>r||s>r){const e={nodeId:y,contrastRatio:r,textColor:t,backgroundColor:K,thresholdsViolated:{aa:o>r,aaa:s>r,apca:!1}};n.has(i)?n.get(i).push(e):n.set(i,[e])}}}b.checkForUnusedPositionValues(d,y,w,D,z,U,_,B),u(w[x])||p(w[x])||b.checkForUnusedWidthAndHeightValues(d,y,w,j,H,G),-1===q||v(w[x],w[j])||b.checkForInvalidVerticalAlignment(d,y,w,j,q)}}return{backgroundColors:t,textColors:i,textColorContrastIssues:n,fillColors:r,borderColors:a,fontInfo:l,unusedDeclarations:d,elementCount:m}}getComputedStyleForNode(e){return this.#i.invoke_getComputedStyleForNode({nodeId:e})}async getMediaQueries(){const e=await this.#i.invoke_getMediaQueries(),t=new Map;if(!e)return t;for(const i of e.medias){if("linkedSheet"===i.source)continue;const e=t.get(i.text)||[];e.push(i),t.set(i.text,e)}return t}async getGlobalStylesheetStats(){const{result:e}=await this.#t.invoke_evaluate({expression:"(function() {\n let styleRules = 0;\n let inlineStyles = 0;\n let externalSheets = 0;\n const stats = {\n // Simple.\n type: new Set(),\n class: new Set(),\n id: new Set(),\n universal: new Set(),\n attribute: new Set(),\n\n // Non-simple.\n nonSimple: new Set()\n };\n\n for (const styleSheet of document.styleSheets) {\n if (styleSheet.href) {\n externalSheets++;\n } else {\n inlineStyles++;\n }\n\n // Attempting to grab rules can trigger a DOMException.\n // Try it and if it fails skip to the next stylesheet.\n let rules;\n try {\n rules = styleSheet.rules;\n } catch (err) {\n continue;\n }\n\n for (const rule of rules) {\n if ('selectorText' in rule) {\n styleRules++;\n\n // Each group that was used.\n for (const selectorGroup of rule.selectorText.split(',')) {\n // Each selector in the group.\n for (const selector of selectorGroup.split(/[\\t\\n\\f\\r ]+/g)) {\n if (selector.startsWith('.')) {\n // Class.\n stats.class.add(selector);\n } else if (selector.startsWith('#')) {\n // Id.\n stats.id.add(selector);\n } else if (selector.startsWith('*')) {\n // Universal.\n stats.universal.add(selector);\n } else if (selector.startsWith('[')) {\n // Attribute.\n stats.attribute.add(selector);\n } else {\n // Type or non-simple selector.\n const specialChars = /[#.:\\[\\]|\\+>~]/;\n if (specialChars.test(selector)) {\n stats.nonSimple.add(selector);\n } else {\n stats.type.add(selector);\n }\n }\n }\n }\n }\n }\n }\n\n return {\n styleRules,\n inlineStyles,\n externalSheets,\n stats: {\n // Simple.\n type: stats.type.size,\n class: stats.class.size,\n id: stats.id.size,\n universal: stats.universal.size,\n attribute: stats.attribute.size,\n\n // Non-simple.\n nonSimple: stats.nonSimple.size\n }\n }\n })()",returnByValue:!0});if("object"===e.type)return e.value}}t.SDKModel.SDKModel.register(C,{capabilities:2,autostart:!1});var y=Object.freeze({__proto__:null,CSSOverviewModel:C});const x=new CSSStyleSheet;x.replaceSync(".overview-processing-view{overflow:hidden;padding:16px;justify-content:center;align-items:center;height:100%}.overview-processing-view h1{font-size:16px;text-align:center;font-weight:normal;margin:0;padding:8px}.overview-processing-view h2{font-size:12px;text-align:center;font-weight:normal;margin:0;padding-top:32px}\n/*# sourceURL=cssOverviewProcessingView.css */\n");const k={cancel:"Cancel"},$=i.i18n.registerUIStrings("panels/css_overview/CSSOverviewProcessingView.ts",k),I=i.i18n.getLocalizedString.bind(void 0,$);class T extends n.Widget.Widget{#n;fragment;constructor(e){super(),this.#n=e,this.#r()}#r(){const e=n.UIUtils.createTextButton(I(k.cancel),(()=>this.#n.dispatchEventToListeners("RequestOverviewCancel")),{jslogContext:"css-overview.cancel-processing",variant:"outlined"});this.setDefaultFocusedElement(e),this.fragment=n.Fragment.Fragment.build`
<div class="vbox overview-processing-view">
<h1>Processing page</h1>
<div>${e}</div>
</div>
`,this.contentElement.appendChild(this.fragment.element()),this.contentElement.style.overflow="auto"}wasShown(){super.wasShown(),this.registerCSSFiles([x])}}var M=Object.freeze({__proto__:null,CSSOverviewProcessingView:T});const A=new CSSStyleSheet;A.replaceSync('.overview-completed-view{overflow:auto;--overview-default-padding:28px;--overview-icon-padding:32px}.overview-completed-view .summary ul,\n.overview-completed-view .colors ul{display:flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}.overview-completed-view .summary ul{display:grid;grid-template-columns:repeat(auto-fill,140px);grid-gap:16px}.overview-completed-view .colors ul li{display:inline-block;margin:0 0 16px;padding:0 8px 0 0}.overview-completed-view .summary ul li{display:flex;flex-direction:column;grid-column-start:auto}.overview-completed-view li .label{font-size:12px;padding-bottom:2px}.overview-completed-view li .value{font-size:17px}.overview-completed-view ul li span{font-weight:bold}.unused-rules-grid .header-container,\n.unused-rules-grid .data-container,\n.unused-rules-grid table.data{position:relative}.unused-rules-grid .data-container{top:0;max-height:350px}.unused-rules-grid{border-left:none;border-right:none}.unused-rules-grid .monospace{display:block;height:18px}.element-grid{flex:1;border-left:none;border-right:none;overflow:auto}.block{width:65px;height:25px;border-radius:3px;margin-right:16px}.block-title{padding-top:4px;font-size:12px;color:var(--sys-color-on-surface);letter-spacing:0;text-transform:uppercase}.block-title.color-text{text-transform:none;max-width:65px;text-overflow:ellipsis;white-space:nowrap;cursor:text;user-select:text;overflow:hidden}.results-section{flex-shrink:0;border-bottom:1px solid var(--sys-color-divider);padding:var(--overview-default-padding) 0 var(--overview-default-padding) 0}.horizontally-padded{padding-left:var(--overview-default-padding);padding-right:var(--overview-default-padding)}.results-section h1{font-size:15px;font-weight:normal;padding:0;margin:0 0 20px;padding-left:calc(var(--overview-default-padding) + var(--overview-icon-padding));position:relative;height:26px;line-height:26px}.results-section h1::before{content:"";display:block;position:absolute;left:var(--overview-default-padding);top:0;width:26px;height:26px;background-image:var(--image-file-cssoverview_icons_2x);background-size:104px 26px}.results-section.horizontally-padded h1{padding-left:var(--overview-icon-padding)}.results-section.horizontally-padded h1::before{left:0}.results-section.summary h1{padding-left:0}.results-section.summary h1::before{display:none}.results-section.colors h1::before{background-position:0 0}.results-section.font-info h1::before{background-position:-26px 0}.results-section.unused-declarations h1::before{background-position:-52px 0}.results-section.media-queries h1::before{background-position:-78px 0}.results-section.colors h2{margin-top:20px;font-size:13px;font-weight:normal}.overview-completed-view .font-info ul,\n.overview-completed-view .media-queries ul,\n.overview-completed-view .unused-declarations ul{width:100%;list-style:none;margin:0;padding:0 var(--overview-default-padding)}.overview-completed-view .font-info ul li,\n.overview-completed-view .media-queries ul li,\n.overview-completed-view .unused-declarations ul li{display:grid;grid-template-columns:2fr 3fr;grid-gap:12px;margin-bottom:4px;align-items:center}.overview-completed-view .font-info button .details,\n.overview-completed-view .media-queries button .details,\n.overview-completed-view .unused-declarations button .details{min-width:100px;text-align:right;margin-right:8px;color:var(--sys-color-primary);pointer-events:none}.overview-completed-view .font-info button .bar-container,\n.overview-completed-view .media-queries button .bar-container,\n.overview-completed-view .unused-declarations button .bar-container{flex:1;pointer-events:none}.overview-completed-view .font-info button .bar,\n.overview-completed-view .media-queries button .bar,\n.overview-completed-view .unused-declarations button .bar{height:8px;background:var(--sys-color-primary-bright);border-radius:2px;min-width:2px}.overview-completed-view .font-info button,\n.overview-completed-view .media-queries button,\n.overview-completed-view .unused-declarations button{border:none;padding:0;padding-right:10px;margin:0;display:flex;align-items:center;border-radius:2px;cursor:pointer;height:28px;background:none;&:focus-visible{outline:2px solid var(--sys-color-state-focus-ring)}&:hover{border-radius:12px;background:var(--sys-color-state-hover-on-subtle)}&:hover .details,\n &:focus .details{color:color-mix(in sRGB,var(--sys-color-primary),var(--sys-color-state-hover-on-prominent) 6%)}&:hover .bar,\n &:focus .bar{background-color:color-mix(in sRGB,var(--sys-color-primary-bright),var(--sys-color-state-hover-on-prominent) 6%);color:var(--sys-color-on-primary)}}.overview-completed-view .font-info .font-metric{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));grid-gap:12px}.overview-completed-view .font-info ul{padding:0}.overview-completed-view .font-info ul li{grid-template-columns:1fr 4fr}.overview-completed-view .font-info h2{font-size:14px;font-weight:bold;margin:0 0 1em}.overview-completed-view .font-info h3{font-size:13px;font-weight:normal;font-style:italic;margin:0 0 0.5em}.overview-completed-view .font-info{padding-bottom:0}.overview-completed-view .font-family{padding:var(--overview-default-padding)}.overview-completed-view .font-family:nth-child(2n+1){background:var(--sys-color-cdt-base-container)}.overview-completed-view .font-family:first-of-type{padding-top:0}.contrast-warning{display:flex;align-items:center;margin-top:2px}.contrast-warning .threshold-label{font-weight:normal;width:30px}.contrast-warning devtools-icon{margin-left:2px}.contrast-preview{padding:0 5px}.contrast-container-in-grid{display:flex;align-items:center}.contrast-container-in-grid > *{margin-right:5px;min-width:initial}.data .nodeId-column{align-items:center;display:flex;height:20px}.nodeId-column .monospace{overflow:hidden}.show-element{margin:0 0 0 8px;display:none;cursor:pointer;flex:none;--icon-show-element:var(--icon-default)}.show-element:focus,\n.show-element:hover{--icon-show-element:var(--icon-default-hover)}.nodeId-column:focus-within .show-element,\n.nodeId-column:hover .show-element{display:inline-block}.results-section.colors{forced-color-adjust:none}\n/*# sourceURL=cssOverviewCompletedView.css */\n');const E=new CSSStyleSheet;E.replaceSync(".overview-sidebar-panel{overflow:auto;display:flex;background:var(--sys-color-cdt-base-container)}.overview-sidebar-panel-container{min-width:fit-content}.overview-sidebar-panel-item{height:30px;padding-left:30px;display:flex;align-items:center;color:var(--sys-color-on-surface);white-space:nowrap;&:hover{background:var(--sys-color-state-hover-on-subtle)}&:focus{background:var(--sys-color-state-focus-highlight)}&.selected{background:var(--sys-color-tonal-container);color:var(--sys-color-on-tonal-container)}}.overview-toolbar{border-bottom:1px solid var(--sys-color-divider);flex:0 0 auto}.overview-sidebar-panel-item:focus-visible{outline-width:unset}@media (forced-colors: active){.overview-sidebar-panel-item.selected{forced-color-adjust:none;background:Highlight;color:HighlightText}.overview-sidebar-panel-item:hover{forced-color-adjust:none;background:Highlight;color:HighlightText}}\n/*# sourceURL=cssOverviewSidebarPanel.css */\n");const L={clearOverview:"Clear overview",cssOverviewPanelSidebar:"CSS overview panel sidebar"},F=i.i18n.registerUIStrings("panels/css_overview/CSSOverviewSidebarPanel.ts",L),O=i.i18n.getLocalizedString.bind(void 0,F),R="overview-sidebar-panel-item",V="selected";class P extends(e.ObjectWrapper.eventMixin(n.Widget.VBox)){containerElement;constructor(){super(!0),this.contentElement.classList.add("overview-sidebar-panel"),this.contentElement.addEventListener("click",this.#a.bind(this)),this.contentElement.addEventListener("keydown",this.#l.bind(this)),this.containerElement=this.contentElement.createChild("div","overview-sidebar-panel-container"),n.ARIAUtils.setLabel(this.containerElement,O(L.cssOverviewPanelSidebar)),n.ARIAUtils.markAsTree(this.containerElement);const e=new n.Toolbar.ToolbarButton(O(L.clearOverview),"clear",void 0,"css-overview.clear-overview");e.addEventListener("Click",this.#d,this);const t=this.containerElement.createChild("div","overview-toolbar");new n.Toolbar.Toolbar("",t).appendToolbarItem(e)}addItem(e,t){const i=this.containerElement.createChild("div",R);i.setAttribute("jslog",`${h.item().track({click:!0,keydown:"Enter|ArrowUp|ArrowDown"}).context(`css-overview.${t}`)}`),n.ARIAUtils.markAsTreeitem(i),i.textContent=e,i.dataset.id=t,i.tabIndex=0}#d(){this.dispatchEventToListeners("Reset")}#c(){this.containerElement.querySelectorAll(`.${R}`).forEach((e=>{e.classList.remove(V)}))}#a(e){const t=e.composedPath()[0];if(!t.classList.contains(R))return;const{id:i}=t.dataset;i&&(this.select(i,!1),this.dispatchEventToListeners("ItemSelected",{id:i,isMouseEvent:!0,key:void 0}))}#l(e){if("Enter"!==e.key&&"ArrowUp"!==e.key&&"ArrowDown"!==e.key)return;const t=e.composedPath()[0];if(!t.classList.contains(R))return;const{id:i}=t.dataset;if(i){if("Enter"===e.key)this.select(i,!1),this.dispatchEventToListeners("ItemSelected",{id:i,isMouseEvent:!1,key:e.key});else{const t=this.containerElement.querySelectorAll(`.${R}`);let o=-1;for(let e=0;e<t.length;e++)if(t[e].dataset.id===i){o=e;break}if(o<0)return;const s=t[(o+("ArrowDown"===e.key?1:-1))%t.length].dataset.id;if(!s)return;this.select(s,!0),this.dispatchEventToListeners("ItemSelected",{id:s,isMouseEvent:!1,key:e.key})}e.consume(!0)}}select(e,t){const i=this.containerElement.querySelector(`[data-id=${CSS.escape(e)}]`);i&&(i.classList.contains(V)||(this.#c(),i.classList.add(V),t&&(i.contentEditable="true",i.focus(),i.contentEditable="false")))}wasShown(){super.wasShown(),this.registerCSSFiles([E])}}var N=Object.freeze({__proto__:null,CSSOverviewSidebarPanel:P});const W={overviewSummary:"Overview summary",colors:"Colors",fontInfo:"Font info",unusedDeclarations:"Unused declarations",mediaQueries:"Media queries",elements:"Elements",externalStylesheets:"External stylesheets",inlineStyleElements:"Inline style elements",styleRules:"Style rules",typeSelectors:"Type selectors",idSelectors:"ID selectors",classSelectors:"Class selectors",universalSelectors:"Universal selectors",attributeSelectors:"Attribute selectors",nonsimpleSelectors:"Non-simple selectors",backgroundColorsS:"Background colors: {PH1}",textColorsS:"Text colors: {PH1}",fillColorsS:"Fill colors: {PH1}",borderColorsS:"Border colors: {PH1}",thereAreNoFonts:"There are no fonts.",thereAreNoUnusedDeclarations:"There are no unused declarations.",thereAreNoMediaQueries:"There are no media queries.",contrastIssues:"Contrast issues",nOccurrences:"{n, plural, =1 {# occurrence} other {# occurrences}}",contrastIssuesS:"Contrast issues: {PH1}",textColorSOverSBackgroundResults:"Text color {PH1} over {PH2} background results in low contrast for {PH3} elements",aa:"AA",aaa:"AAA",apca:"APCA",element:"Element",declaration:"Declaration",source:"Source",contrastRatio:"Contrast ratio",cssOverviewElements:"CSS overview elements",showElement:"Show element"},D=i.i18n.registerUIStrings("panels/css_overview/CSSOverviewCompletedView.ts",W),z=i.i18n.getLocalizedString.bind(void 0,D);function _(e){let{h:t,s:i,l:o}=e.as("hsl");return t=Math.round(360*t),i=Math.round(100*i),o=Math.round(100*o),o=Math.max(0,o-15),`1px solid hsl(${t}deg ${i}% ${o}%)`}class B extends n.Widget.VBox{#h;#n;#u;#p;#v;#m;#g;#w;#f;#b;#S;#C;#y;constructor(e){super(),this.#n=e,this.#u=new Intl.NumberFormat("en-US"),this.#h=new n.SplitWidget.SplitWidget(!0,!1,void 0,200),this.#h.show(this.element),this.#p=new n.SplitWidget.SplitWidget(!0,!0),this.#v=new n.Widget.VBox,this.#m=new U,this.#m.addEventListener("TabClosed",(e=>{0===e.data&&this.#p.setSidebarMinimized(!0)})),this.#p.setMainWidget(this.#v),this.#p.setSidebarWidget(this.#m),this.#p.setVertical(!1),this.#p.setSecondIsSidebar(!0),this.#p.setSidebarMinimized(!0),this.#g=new P,this.#g.setMinimumSize(100,25),this.#h.setSidebarWidget(this.#g),this.#h.setMainWidget(this.#p),this.#b=new c.Linkifier.Linkifier(20,!0),this.#S=new Map,this.#g.addItem(z(W.overviewSummary),"summary"),this.#g.addItem(z(W.colors),"colors"),this.#g.addItem(z(W.fontInfo),"font-info"),this.#g.addItem(z(W.unusedDeclarations),"unused-declarations"),this.#g.addItem(z(W.mediaQueries),"media-queries"),this.#g.select("summary",!1),this.#g.addEventListener("ItemSelected",this.#x,this),this.#g.addEventListener("Reset",this.#k,this),this.#n.addEventListener("Reset",this.#d,this),this.#n.addEventListener("PopulateNodes",this.#$,this),this.#v.element.addEventListener("click",this.#I.bind(this)),this.#C=null}wasShown(){super.wasShown(),this.#p.registerCSSFiles([A]),this.registerCSSFiles([A])}initializeModels(e){const i=e.model(t.CSSModel.CSSModel),o=e.model(t.DOMModel.DOMModel);if(!i||!o)throw new Error("Target must provide CSS and DOM models");this.#w=i,this.#f=o}#x(e){const{data:t}=e,i=this.#y.$(t.id);if(i&&(i.scrollIntoView(),!t.isMouseEvent&&"Enter"===t.key)){const e=i.querySelector('button, [tabindex="0"]');e?.focus()}}#k(){this.#n.dispatchEventToListeners("Reset")}#d(){this.#v.element.removeChildren(),this.#p.setSidebarMinimized(!0),this.#m.closeTabs(),this.#S=new Map,B.pushedNodes.clear(),this.#g.select("summary",!1)}#I(e){if(!e.target)return;const t=e.target.dataset,i=t.type;if(!i||!this.#C)return;let o;switch(i){case"contrast":{const e=t.section,s=t.key;if(!s)return;o={type:i,key:s,nodes:this.#C.textColorContrastIssues.get(s)||[],section:e};break}case"color":{const e=t.color,s=t.section;if(!e)return;let n;switch(s){case"text":n=this.#C.textColors.get(e);break;case"background":n=this.#C.backgroundColors.get(e);break;case"fill":n=this.#C.fillColors.get(e);break;case"border":n=this.#C.borderColors.get(e)}if(!n)return;n=Array.from(n).map((e=>({nodeId:e}))),o={type:i,color:e,nodes:n,section:s};break}case"unused-declarations":{const e=t.declaration;if(!e)return;const s=this.#C.unusedDeclarations.get(e);if(!s)return;o={type:i,declaration:e,nodes:s};break}case"media-queries":{const e=t.text;if(!e)return;const s=this.#C.mediaQueries.get(e);if(!s)return;o={type:i,text:e,nodes:s};break}case"font-info":{const e=t.value;if(!t.path)return;const[s,n]=t.path.split("/");if(!e)return;const r=this.#C.fontInfo.get(s);if(!r)return;const a=r.get(n);if(!a)return;const l=a.get(e);if(!l)return;o={type:i,name:`${e} (${s}, ${n})`,nodes:l.map((e=>({nodeId:e})))};break}default:return}e.consume(),this.#n.dispatchEventToListeners("PopulateNodes",{payload:o}),this.#p.setSidebarMinimized(!1)}async#r(e){if(!e||!("backgroundColors"in e)||!("textColors"in e))return;this.#C=e;const{elementCount:t,backgroundColors:i,textColors:o,textColorContrastIssues:s,fillColors:r,borderColors:a,globalStyleStats:l,mediaQueries:d,unusedDeclarations:c,fontInfo:h}=this.#C,u=this.#T(i),p=this.#T(o),v=this.#T(r),m=this.#T(a);this.#y=n.Fragment.Fragment.build`
<div class="vbox overview-completed-view">
<div $="summary" class="results-section horizontally-padded summary">
<h1>${z(W.overviewSummary)}</h1>
<ul>
<li>
<div class="label">${z(W.elements)}</div>
<div class="value">${this.#u.format(t)}</div>
</li>
<li>
<div class="label">${z(W.externalStylesheets)}</div>
<div class="value">${this.#u.format(l.externalSheets)}</div>
</li>
<li>
<div class="label">${z(W.inlineStyleElements)}</div>
<div class="value">${this.#u.format(l.inlineStyles)}</div>
</li>
<li>
<div class="label">${z(W.styleRules)}</div>
<div class="value">${this.#u.format(l.styleRules)}</div>
</li>
<li>
<div class="label">${z(W.mediaQueries)}</div>
<div class="value">${this.#u.format(d.size)}</div>
</li>
<li>
<div class="label">${z(W.typeSelectors)}</div>
<div class="value">${this.#u.format(l.stats.type)}</div>
</li>
<li>
<div class="label">${z(W.idSelectors)}</div>
<div class="value">${this.#u.format(l.stats.id)}</div>
</li>
<li>
<div class="label">${z(W.classSelectors)}</div>
<div class="value">${this.#u.format(l.stats.class)}</div>
</li>
<li>
<div class="label">${z(W.universalSelectors)}</div>
<div class="value">${this.#u.format(l.stats.universal)}</div>
</li>
<li>
<div class="label">${z(W.attributeSelectors)}</div>
<div class="value">${this.#u.format(l.stats.attribute)}</div>
</li>
<li>
<div class="label">${z(W.nonsimpleSelectors)}</div>
<div class="value">${this.#u.format(l.stats.nonSimple)}</div>
</li>
</ul>
</div>
<div $="colors" class="results-section horizontally-padded colors">
<h1>${z(W.colors)}</h1>
<h2>${z(W.backgroundColorsS,{PH1:u.length})}</h2>
<ul>
${u.map(this.#M.bind(this,"background"))}
</ul>
<h2>${z(W.textColorsS,{PH1:p.length})}</h2>
<ul>
${p.map(this.#M.bind(this,"text"))}
</ul>
${s.size>0?this.#A(s):""}
<h2>${z(W.fillColorsS,{PH1:v.length})}</h2>
<ul>
${v.map(this.#M.bind(this,"fill"))}
</ul>
<h2>${z(W.borderColorsS,{PH1:m.length})}</h2>
<ul>
${m.map(this.#M.bind(this,"border"))}
</ul>
</div>
<div $="font-info" class="results-section font-info">
<h1>${z(W.fontInfo)}</h1>
${h.size>0?this.#E(h):n.Fragment.Fragment.build`<div>${z(W.thereAreNoFonts)}</div>`}
</div>
<div $="unused-declarations" class="results-section unused-declarations">
<h1>${z(W.unusedDeclarations)}</h1>
${c.size>0?this.#L(c,"unused-declarations","declaration"):n.Fragment.Fragment.build`<div class="horizontally-padded">${z(W.thereAreNoUnusedDeclarations)}</div>`}
</div>
<div $="media-queries" class="results-section media-queries">
<h1>${z(W.mediaQueries)}</h1>
${d.size>0?this.#L(d,"media-queries","text"):n.Fragment.Fragment.build`<div class="horizontally-padded">${z(W.thereAreNoMediaQueries)}</div>`}
</div>
</div>`,this.#v.element.appendChild(this.#y.element())}#$(e){const{payload:t}=e.data;let i="",o="";switch(t.type){case"contrast":{const{section:e,key:s}=t;i=`${e}-${s}`,o=z(W.contrastIssues);break}case"color":{const{section:e,color:s}=t;i=`${e}-${s}`,o=`${s.toUpperCase()} (${e})`;break}case"unused-declarations":{const{declaration:e}=t;i=`${e}`,o=`${e}`;break}case"media-queries":{const{text:e}=t;i=`${e}`,o=`${e}`;break}case"font-info":{const{name:e}=t;i=`${e}`,o=`${e}`;break}}let s=this.#S.get(i);if(!s){if(!this.#f||!this.#w)throw new Error("Unable to initialize CSS overview, missing models");s=new j(this.#n,this.#f,this.#w,this.#b),s.populateNodes(t.nodes),this.#S.set(i,s)}this.#m.appendTab(i,o,s,t.type)}#E(e){const t=Array.from(e.entries());return n.Fragment.Fragment.build`
${t.map((([e,t])=>n.Fragment.Fragment.build`<section class="font-family"><h2>${e}</h2> ${this.#F(e,t)}</section>`))}
`}#F(e,t){const i=Array.from(t.entries());return n.Fragment.Fragment.build`
<div class="font-metric">
${i.map((([t,i])=>{const o=`${e}/${t}`;return n.Fragment.Fragment.build`
<div>
<h3>${t}</h3>
${this.#L(i,"font-info","value",o)}
</div>`}))}
</div>`}#L(e,t,i,o=""){const s=Array.from(e.entries()).sort(((e,t)=>{const i=e[1];return t[1].length-i.length})),r=s.reduce(((e,t)=>e+t[1].length),0);return n.Fragment.Fragment.build`<ul>
${s.map((([e,s])=>{const a=100*s.length/r,l=z(W.nOccurrences,{n:s.length});return n.Fragment.Fragment.build`<li>
<div class="title">${e}</div>
<button data-type="${t}" data-path="${o}" data-${i}="${e}"
jslog="${h.action().track({click:!0}).context(`css-overview.${t}`)}">
<div class="details">${l}</div>
<div class="bar-container">
<div class="bar" style="width: ${a}%;"></div>
</div>
</button>
</li>`}))}
</ul>`}#A(e){return n.Fragment.Fragment.build`
<h2>${z(W.contrastIssuesS,{PH1:e.size})}</h2>
<ul>
${[...e.entries()].map((([e,t])=>this.#O(e,t)))}
</ul>
`}#O(e,t){console.assert(t.length>0);let i=t[0];for(const e of t)Math.abs(e.contrastRatio)<Math.abs(i.contrastRatio)&&(i=e);const s=i.textColor.asString("hexa"),r=i.backgroundColor.asString("hexa"),a=o.Runtime.experiments.isEnabled("apca"),l=z(W.textColorSOverSBackgroundResults,{PH1:s,PH2:r,PH3:t.length}),d=n.Fragment.Fragment.build`<li>
<button
title="${l}" aria-label="${l}"
data-type="contrast" data-key="${e}" data-section="contrast" class="block" $="color"
jslog="${h.action("css-overview.contrast").track({click:!0})}">
Text
</button>
<div class="block-title">
<div class="contrast-warning hidden" $="aa"><span class="threshold-label">${z(W.aa)}</span></div>
<div class="contrast-warning hidden" $="aaa"><span class="threshold-label">${z(W.aaa)}</span></div>
<div class="contrast-warning hidden" $="apca"><span class="threshold-label">${z(W.apca)}</span></div>
</div>
</li>`;if(a){const e=d.$("apca");i.thresholdsViolated.apca?e.appendChild(G()):e.appendChild(q()),e.classList.remove("hidden")}else{const e=d.$("aa");i.thresholdsViolated.aa?e.appendChild(G()):e.appendChild(q());const t=d.$("aaa");i.thresholdsViolated.aaa?t.appendChild(G()):t.appendChild(q()),e.classList.remove("hidden"),t.classList.remove("hidden")}const c=d.$("color");return c.style.backgroundColor=r,c.style.color=s,c.style.border=_(i.backgroundColor.asLegacyColor()),d}#M(t,i){const o=n.Fragment.Fragment.build`<li>
<button title=${i} data-type="color" data-color="${i}"
data-section="${t}" class="block" $="color"
jslog="${h.action("css-overview.color").track({click:!0})}"></button>
<div class="block-title color-text">${i}</div>
</li>`,s=o.$("color");s.style.backgroundColor=i;const r=e.Color.parse(i)?.asLegacyColor();if(r)return s.style.border=_(r),o}#T(t){return Array.from(t.keys()).sort(((t,i)=>{const o=e.Color.parse(t)?.asLegacyColor(),s=e.Color.parse(i)?.asLegacyColor();return o&&s?e.ColorUtils.luminance(s.rgba())-e.ColorUtils.luminance(o.rgba()):0}))}setOverviewData(e){this.#r(e)}static pushedNodes=new Set}class U extends(e.ObjectWrapper.eventMixin(n.Widget.VBox)){#R;constructor(){super(),this.#R=new n.TabbedPane.TabbedPane,this.#R.show(this.element),this.#R.addEventListener(n.TabbedPane.Events.TabClosed,(()=>{this.dispatchEventToListeners("TabClosed",this.#R.tabIds().length)}))}appendTab(e,t,i,o){this.#R.hasTab(e)||this.#R.appendTab(e,t,i,void 0,void 0,!0,void 0,void 0,o),this.#R.selectTab(e)}closeTabs(){this.#R.closeTabs(this.#R.tabIds())}}class j extends n.Widget.Widget{#n;#f;#w;#b;#V;#P;constructor(e,t,i,o){super(),this.#n=e,this.#f=t,this.#w=i,this.#b=o,this.#V=[{id:"node-id",title:z(W.element),sortable:!0,weight:50,titleDOMFragment:void 0,sort:void 0,align:void 0,width:void 0,fixedWidth:void 0,editable:void 0,nonSelectable:void 0,longText:void 0,disclosure:void 0,allowInSortByEvenWhenHidden:void 0,dataType:void 0,defaultWeight:void 0},{id:"declaration",title:z(W.declaration),sortable:!0,weight:50,titleDOMFragment:void 0,sort:void 0,align:void 0,width:void 0,fixedWidth:void 0,editable:void 0,nonSelectable:void 0,longText:void 0,disclosure:void 0,allowInSortByEvenWhenHidden:void 0,dataType:void 0,defaultWeight:void 0},{id:"source-url",title:z(W.source),sortable:!1,weight:100,titleDOMFragment:void 0,sort:void 0,align:void 0,width:void 0,fixedWidth:void 0,editable:void 0,nonSelectable:void 0,longText:void 0,disclosure:void 0,allowInSortByEvenWhenHidden:void 0,dataType:void 0,defaultWeight:void 0},{id:"contrast-ratio",title:z(W.contrastRatio),sortable:!0,weight:25,titleDOMFragment:void 0,sort:void 0,align:void 0,width:"150px",fixedWidth:!0,editable:void 0,nonSelectable:void 0,longText:void 0,disclosure:void 0,allowInSortByEvenWhenHidden:void 0,dataType:void 0,defaultWeight:void 0}],this.#P=new d.SortableDataGrid.SortableDataGrid({displayName:z(W.cssOverviewElements),columns:this.#V,editCallback:void 0,deleteCallback:void 0,refreshCallback:void 0}),this.#P.element.classList.add("element-grid"),this.#P.element.addEventListener("mouseover",this.#N.bind(this)),this.#P.setStriped(!0),this.#P.addEventListener("SortingChanged",this.#W.bind(this)),this.#P.asWidget().show(this.element)}#W(){const e=this.#P.sortColumnId();if(!e)return;const t=d.SortableDataGrid.SortableDataGrid.StringComparator.bind(null,e);this.#P.sortNodes(t,!this.#P.isSortOrderAscending())}#N(e){const t=e.composedPath().find((e=>e.dataset&&e.dataset.backendNodeId));if(!t)return;const i=Number(t.dataset.backendNodeId);this.#n.dispatchEventToListeners("RequestNodeHighlight",i)}async populateNodes(e){if(this.#P.rootNode().removeChildren(),!e.length)return;const[t]=e,i=new Set;let o;if("nodeId"in t&&t.nodeId&&i.add("node-id"),"declaration"in t&&t.declaration&&i.add("declaration"),"sourceURL"in t&&t.sourceURL&&i.add("source-url"),"contrastRatio"in t&&t.contrastRatio&&i.add("contrast-ratio"),"nodeId"in t&&i.has("node-id")){const t=e.reduce(((e,t)=>{const i=t.nodeId;return B.pushedNodes.has(i)?e:(B.pushedNodes.add(i),e.add(i))}),new Set);o=await this.#f.pushNodesByBackendIdsToFrontend(t)}for(const t of e){let e;if("nodeId"in t&&i.has("node-id")){if(!o)continue;if(e=o.get(t.nodeId),!e)continue}const s=new H(t,e,this.#b,this.#w);s.selectable=!1,this.#P.insertChild(s)}this.#P.setColumnsVisibility(i),this.#P.renderInline(),this.#P.wasShown()}}class H extends d.SortableDataGrid.SortableDataGridNode{#b;#w;#D;constructor(e,t,i,o){super(e),this.#D=t,this.#b=i,this.#w=o}createCell(t){const i=this.#D;if("node-id"===t){const o=this.createTD(t);if(o.textContent="...",!i)throw new Error("Node entry is missing a related frontend node.");return e.Linkifier.Linkifier.linkify(i).then((e=>{o.textContent="",e.dataset.backendNodeId=i.backendNodeId().toString(),o.appendChild(e);const t=new l.Icon.Icon;t.data={iconName:"select-element",color:"var(--icon-show-element)",width:"16px"},t.classList.add("show-element"),n.Tooltip.Tooltip.install(t,z(W.showElement)),t.tabIndex=0,t.onclick=()=>i.scrollIntoView(),o.appendChild(t)})),o}if("source-url"===t){const e=this.createTD(t);if(this.data.range){const t=this.#z(this.#w,this.#b,this.data.styleSheetId,a.TextRange.TextRange.fromObject(this.data.range));t&&""!==t.textContent?e.appendChild(t):e.textContent="(unable to link)"}else e.textContent="(unable to link to inlined styles)";return e}if("contrast-ratio"===t){const e=this.createTD(t),i=o.Runtime.experiments.isEnabled("apca"),s=r.NumberUtilities.floor(this.data.contrastRatio,2),a=i?s+"%":s,l=_(this.data.backgroundColor),d=this.data.textColor.asString(),c=this.data.backgroundColor.asString(),h=n.Fragment.Fragment.build`
<div class="contrast-container-in-grid" $="container">
<span class="contrast-preview" style="border: ${l};
color: ${d};
background-color: ${c};">Aa</span>
<span>${a}</span>
</div>
`,u=h.$("container");return i?(u.append(n.Fragment.Fragment.build`<span>${z(W.apca)}</span>`.element()),this.data.thresholdsViolated.apca?u.appendChild(G()):u.appendChild(q())):(u.append(n.Fragment.Fragment.build`<span>${z(W.aa)}</span>`.element()),this.data.thresholdsViolated.aa?u.appendChild(G()):u.appendChild(q()),u.append(n.Fragment.Fragment.build`<span>${z(W.aaa)}</span>`.element()),this.data.thresholdsViolated.aaa?u.appendChild(G()):u.appendChild(q())),e.appendChild(h.element()),e}return super.createCell(t)}#z(e,i,o,s){const n=e.styleSheetHeaderForId(o);if(!n)return;const r=n.lineNumberInSource(s.startLine),a=n.columnNumberInSource(s.startLine,s.startColumn),l=new t.CSSModel.CSSLocation(n,r,a);return i.linkifyCSSLocation(l)}}function G(){const e=new l.Icon.Icon;return e.data={iconName:"clear",color:"var(--icon-error)",width:"14px",height:"14px"},e}function q(){const e=new l.Icon.Icon;return e.data={iconName:"checkmark",color:"var(--icon-checkmark-green)",width:"14px",height:"14px"},e}var Q=Object.freeze({__proto__:null,CSSOverviewCompletedView:B,DetailsView:U,ElementDetailsView:j,ElementNode:H});const K=new CSSStyleSheet;K.replaceSync(".css-overview-panel{overflow:hidden}devtools-css-overview-start-view{overflow:auto}\n/*# sourceURL=cssOverview.css */\n");class J extends n.Panel.Panel{#n;#_;#B;#U;#j;#H;#G;#q;#Q;#K;#J;#X;#Y;#Z;#ee;constructor(e){super("css-overview"),this.element.classList.add("css-overview-panel"),this.#n=e,this.#_=new u.CSSOverviewStartView.CSSOverviewStartView,this.#_.addEventListener("overviewstartrequested",(()=>this.#n.dispatchEventToListeners("RequestOverviewStart"))),this.#B=new T(this.#n),this.#U=new B(this.#n),t.TargetManager.TargetManager.instance().observeTargets(this),this.#n.addEventListener("RequestOverviewStart",(e=>{p.userMetrics.actionTaken(p.UserMetrics.Action.CaptureCssOverviewClicked),this.#te()}),this),this.#n.addEventListener("OverviewCompleted",this.#ie,this),this.#n.addEventListener("Reset",this.#d,this),this.#n.addEventListener("RequestNodeHighlight",this.#oe,this),this.#d()}targetAdded(e){if(e!==t.TargetManager.TargetManager.instance().primaryPageTarget())return;this.#U.initializeModels(e);const i=e.model(C);this.#j=i}targetRemoved(){}#se(){if(!this.#j)throw new Error("Did not retrieve model information yet.");return this.#j}#d(){this.#H=new Map,this.#G=new Map,this.#q=new Map,this.#Q=new Map,this.#K=new Map,this.#J=new Map,this.#X=new Map,this.#Y=0,this.#Z={styleRules:0,inlineStyles:0,externalSheets:0,stats:{type:0,class:0,id:0,universal:0,attribute:0,nonSimple:0}},this.#ee=new Map,this.#ne()}#oe(e){this.#se().highlightNode(e.data)}#ne(){this.#B.hideWidget(),this.#U.hideWidget(),this.contentElement.append(this.#_),this.#_.show()}#re(){this.#_.hide(),this.#U.hideWidget(),this.#B.show(this.contentElement)}#ae(){this.#_.hide(),this.#B.hideWidget(),this.#U.show(this.contentElement),this.#U.setOverviewData({backgroundColors:this.#H,textColors:this.#G,textColorContrastIssues:this.#ee,fillColors:this.#q,borderColors:this.#Q,globalStyleStats:this.#Z,fontInfo:this.#K,elementCount:this.#Y,mediaQueries:this.#J,unusedDeclarations:this.#X})}async#te(){this.#re();const e=this.#se(),[t,{elementCount:i,backgroundColors:o,textColors:s,textColorContrastIssues:n,fillColors:r,borderColors:a,fontInfo:l,unusedDeclarations:d},c]=await Promise.all([e.getGlobalStylesheetStats(),e.getNodeStyleStats(),e.getMediaQueries()]);i&&(this.#Y=i),t&&(this.#Z=t),c&&(this.#J=c),o&&(this.#H=o),s&&(this.#G=s),n&&(this.#ee=n),r&&(this.#q=r),a&&(this.#Q=a),l&&(this.#K=l),d&&(this.#X=d),this.#n.dispatchEventToListeners("OverviewCompleted")}#ie(){this.#ae()}wasShown(){super.wasShown(),this.registerCSSFiles([K])}}var X=Object.freeze({__proto__:null,CSSOverviewPanel:J});export{Q as CSSOverviewCompletedView,m as CSSOverviewController,y as CSSOverviewModel,X as CSSOverviewPanel,M as CSSOverviewProcessingView,N as CSSOverviewSidebarPanel,S as CSSOverviewUnusedDeclarations};