chrome-devtools-frontend 1.0.1596535 → 1.0.1597624

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/agents/prompts/ui-widgets.md +7 -8
  2. package/docs/ui_engineering.md +10 -11
  3. package/front_end/core/host/AidaClient.ts +4 -0
  4. package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -0
  5. package/front_end/core/host/UserMetrics.ts +12 -0
  6. package/front_end/core/root/Runtime.ts +5 -0
  7. package/front_end/core/sdk/CPUThrottlingManager.ts +14 -13
  8. package/front_end/core/sdk/CSSMatchedStyles.ts +2 -0
  9. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +28 -0
  10. package/front_end/core/sdk/PageResourceLoader.ts +22 -1
  11. package/front_end/devtools_compatibility.js +2 -1
  12. package/front_end/models/ai_assistance/AiConversation.ts +29 -8
  13. package/front_end/models/ai_assistance/ChangeManager.ts +16 -0
  14. package/front_end/models/ai_assistance/ExtensionScope.ts +11 -3
  15. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +127 -0
  16. package/front_end/models/ai_assistance/agents/AiAgent.ts +26 -3
  17. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +1 -1
  18. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +11 -8
  19. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +24 -0
  20. package/front_end/models/ai_assistance/agents/StylingAgent.ts +323 -16
  21. package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
  22. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +27 -0
  23. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +21 -0
  24. package/front_end/models/greendev/Prototypes.ts +7 -1
  25. package/front_end/models/trace/Processor.ts +1 -0
  26. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -0
  27. package/front_end/models/trace/insights/CharacterSet.ts +172 -0
  28. package/front_end/models/trace/insights/Models.ts +1 -0
  29. package/front_end/models/trace/insights/types.ts +1 -0
  30. package/front_end/models/trace/types/TraceEvents.ts +17 -0
  31. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +51 -36
  32. package/front_end/panels/ai_assistance/PatchWidget.ts +6 -6
  33. package/front_end/panels/ai_assistance/components/ChatMessage.ts +93 -74
  34. package/front_end/panels/ai_assistance/components/ChatView.ts +6 -11
  35. package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +18 -9
  36. package/front_end/panels/ai_assistance/components/StylingAgentMarkdownRenderer.ts +200 -0
  37. package/front_end/panels/ai_assistance/components/chatMessage.css +11 -8
  38. package/front_end/panels/application/AppManifestView.ts +3 -4
  39. package/front_end/panels/application/DeviceBoundSessionsView.ts +18 -22
  40. package/front_end/panels/application/FrameDetailsView.ts +9 -15
  41. package/front_end/panels/application/OriginTrialTreeView.ts +2 -3
  42. package/front_end/panels/application/ReportingApiView.ts +13 -17
  43. package/front_end/panels/application/ServiceWorkerCacheViews.ts +1 -1
  44. package/front_end/panels/application/components/BackForwardCacheView.ts +3 -3
  45. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +2 -3
  46. package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +3 -2
  47. package/front_end/panels/changes/ChangesView.ts +6 -4
  48. package/front_end/panels/common/ExtensionServer.ts +15 -0
  49. package/front_end/panels/console/ConsolePinPane.ts +3 -3
  50. package/front_end/panels/coverage/CoverageListView.ts +1 -1
  51. package/front_end/panels/css_overview/CSSOverviewPanel.ts +11 -15
  52. package/front_end/panels/developer_resources/DeveloperResourcesView.ts +3 -5
  53. package/front_end/panels/elements/ElementsTreeElement.ts +55 -47
  54. package/front_end/panels/elements/ElementsTreeOutline.ts +149 -28
  55. package/front_end/panels/elements/EventListenersWidget.ts +3 -2
  56. package/front_end/panels/elements/StandaloneStylesContainer.ts +21 -6
  57. package/front_end/panels/elements/StylePropertyTreeElement.ts +49 -4
  58. package/front_end/panels/layer_viewer/Layers3DView.ts +5 -4
  59. package/front_end/panels/lighthouse/LighthousePanel.ts +8 -0
  60. package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +5 -6
  61. package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +6 -11
  62. package/front_end/panels/network/RequestCookiesView.ts +3 -4
  63. package/front_end/panels/network/RequestInitiatorView.ts +7 -5
  64. package/front_end/panels/network/RequestResponseView.ts +10 -15
  65. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +3 -4
  66. package/front_end/panels/recorder/components/RecordingView.ts +31 -36
  67. package/front_end/panels/recorder/components/StepEditor.ts +6 -7
  68. package/front_end/panels/search/SearchView.ts +2 -3
  69. package/front_end/panels/settings/SettingsScreen.ts +3 -2
  70. package/front_end/panels/settings/WorkspaceSettingsTab.ts +2 -5
  71. package/front_end/panels/timeline/components/LiveMetricsView.ts +5 -8
  72. package/front_end/panels/timeline/components/insights/Cache.ts +8 -10
  73. package/front_end/panels/timeline/components/insights/CharacterSet.ts +38 -0
  74. package/front_end/panels/timeline/components/insights/DOMSize.ts +16 -20
  75. package/front_end/panels/timeline/components/insights/DocumentLatency.ts +2 -6
  76. package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +3 -4
  77. package/front_end/panels/timeline/components/insights/FontDisplay.ts +3 -4
  78. package/front_end/panels/timeline/components/insights/ForcedReflow.ts +5 -7
  79. package/front_end/panels/timeline/components/insights/INPBreakdown.ts +3 -4
  80. package/front_end/panels/timeline/components/insights/ImageDelivery.ts +3 -4
  81. package/front_end/panels/timeline/components/insights/ImageRef.ts +2 -4
  82. package/front_end/panels/timeline/components/insights/InsightRenderer.ts +2 -0
  83. package/front_end/panels/timeline/components/insights/LCPBreakdown.ts +5 -7
  84. package/front_end/panels/timeline/components/insights/LCPDiscovery.ts +2 -4
  85. package/front_end/panels/timeline/components/insights/LegacyJavaScript.ts +3 -4
  86. package/front_end/panels/timeline/components/insights/ModernHTTP.ts +3 -4
  87. package/front_end/panels/timeline/components/insights/NetworkDependencyTree.ts +7 -11
  88. package/front_end/panels/timeline/components/insights/NodeLink.ts +2 -4
  89. package/front_end/panels/timeline/components/insights/RenderBlocking.ts +3 -4
  90. package/front_end/panels/timeline/components/insights/SlowCSSSelector.ts +7 -10
  91. package/front_end/panels/timeline/components/insights/ThirdParties.ts +5 -7
  92. package/front_end/panels/timeline/components/insights/insights.ts +2 -0
  93. package/front_end/panels/web_audio/WebAudioView.ts +3 -4
  94. package/front_end/ui/components/settings/SettingCheckbox.ts +2 -0
  95. package/front_end/ui/legacy/UIUtils.ts +5 -5
  96. package/front_end/ui/legacy/Widget.ts +33 -2
  97. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
  98. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +8 -8
  99. package/front_end/ui/visual_logging/Debugging.ts +0 -32
  100. package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
  101. package/package.json +1 -1
@@ -284,8 +284,8 @@ const UIStrings = {
284
284
  */
285
285
  startAChat: 'Start a chat',
286
286
  /**
287
-    * @description Label of an adorner next to the html node in the Elements panel.
288
-    */
287
+ * @description Label of an adorner next to the html node in the Elements panel.
288
+ */
289
289
  viewSourceCode: 'View source code',
290
290
  /**
291
291
  * @description Context menu item in Elements panel to assess visibility of an element via AI.
@@ -436,7 +436,6 @@ export interface ViewInput {
436
436
  showAiButton: boolean;
437
437
  aiButtonTitle?: string;
438
438
  onAiButtonClick: (e: Event) => void;
439
-
440
439
  decorations: Decoration[];
441
440
  descendantDecorations: Decoration[];
442
441
  decorationsTooltip: string;
@@ -806,16 +805,13 @@ function renderAttribute(
806
805
 
807
806
  // clang-format off
808
807
  return html`<span class="webkit-html-attribute" jslog=${jslog}><span class="webkit-html-attribute-name"
809
- ${animateOn(Boolean(updateRecord?.isAttributeModified(name) && !hasText), DOM_UPDATE_ANIMATION_CLASS_NAME)} ${
810
- relationRefDirective}>${name}</span>${
811
- hasText ? html`=\u200B"<span class="webkit-html-attribute-value" ${
812
- animateOn(
813
- Boolean(updateRecord?.isAttributeModified(name) && hasText),
814
- DOM_UPDATE_ANIMATION_CLASS_NAME)} ${valueRelationRefDirective} ${withEntitiesRef}>
808
+ ${animateOn(Boolean(updateRecord?.isAttributeModified(name) && !hasText), DOM_UPDATE_ANIMATION_CLASS_NAME)} ${relationRefDirective}>${name}</span>${hasText ? html`=\u200B"<span class="webkit-html-attribute-value" ${animateOn(
809
+ Boolean(updateRecord?.isAttributeModified(name) && hasText),
810
+ DOM_UPDATE_ANIMATION_CLASS_NAME)} ${valueRelationRefDirective} ${withEntitiesRef}>
815
811
  ${valueType === ValueType.SRC ? renderLinkifiedValue(value, node) : nothing}
816
812
  ${valueType === ValueType.SRCSET ? renderLinkifiedSrcset(Common.Srcset.parseSrcset(value), node) : nothing}
817
813
  </span>"` :
818
- nothing}</span>`;
814
+ nothing}</span>`;
819
815
  // clang-format on
820
816
  }
821
817
 
@@ -868,15 +864,15 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
868
864
  render(html`
869
865
  <div ${ref(el => { output.contentElement = el as HTMLElement; })}>
870
866
  ${input.node ? html`<span class="highlight">${renderTitle(
871
- input.node,
872
- input.isClosingTag,
873
- input.expanded,
874
- input.isExpandable,
875
- input.isXMLMimeType,
876
- input.updateRecord,
877
- input.onHighlightSearchResults,
878
- input.onExpand,
879
- )}</span>` : nothing}
867
+ input.node,
868
+ input.isClosingTag,
869
+ input.expanded,
870
+ input.isExpandable,
871
+ input.isXMLMimeType,
872
+ input.updateRecord,
873
+ input.onHighlightSearchResults,
874
+ input.onExpand,
875
+ )}</span>` : nothing}
880
876
  ${input.isHovered || input.isSelected ? html`
881
877
  <div class="selection fill" style=${`margin-left: ${-input.indent}px`}></div>
882
878
  ` : nothing}
@@ -913,7 +909,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
913
909
  toggleable=true
914
910
  tabindex=0
915
911
  .name=${ElementsComponents.AdornerManager.RegisteredAdorners.CONTAINER}
916
- jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.CONTAINER).track({click: true})}
912
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.CONTAINER).track({ click: true })}
917
913
  active=${input.containerAdornerActive}
918
914
  aria-label=${input.containerAdornerActive ? i18nString(UIStrings.enableContainer) : i18nString(UIStrings.disableContainer)}
919
915
  @click=${input.onContainerAdornerClick}
@@ -930,7 +926,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
930
926
  toggleable=true
931
927
  tabindex=0
932
928
  .name=${ElementsComponents.AdornerManager.RegisteredAdorners.FLEX}
933
- jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.FLEX).track({click: true})}
929
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.FLEX).track({ click: true })}
934
930
  active=${input.flexAdornerActive}
935
931
  aria-label=${input.flexAdornerActive ? i18nString(UIStrings.disableFlexMode) : i18nString(UIStrings.enableFlexMode)}
936
932
  @click=${input.onFlexAdornerClick}
@@ -944,7 +940,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
944
940
  toggleable=true
945
941
  tabindex=0
946
942
  .name=${input.isSubgrid ? ElementsComponents.AdornerManager.RegisteredAdorners.SUBGRID : ElementsComponents.AdornerManager.RegisteredAdorners.GRID}
947
- jslog=${VisualLogging.adorner(input.isSubgrid ? ElementsComponents.AdornerManager.RegisteredAdorners.SUBGRID : ElementsComponents.AdornerManager.RegisteredAdorners.GRID).track({click: true})}
943
+ jslog=${VisualLogging.adorner(input.isSubgrid ? ElementsComponents.AdornerManager.RegisteredAdorners.SUBGRID : ElementsComponents.AdornerManager.RegisteredAdorners.GRID).track({ click: true })}
948
944
  active=${input.gridAdornerActive}
949
945
  aria-label=${input.gridAdornerActive ? i18nString(UIStrings.disableGridMode) : i18nString(UIStrings.enableGridMode)}
950
946
  @click=${input.onGridAdornerClick}
@@ -958,7 +954,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
958
954
  toggleable=true
959
955
  tabindex=0
960
956
  .name=${ElementsComponents.AdornerManager.RegisteredAdorners.GRID_LANES}
961
- jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.GRID_LANES).track({click: true})}
957
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.GRID_LANES).track({ click: true })}
962
958
  active=${input.gridAdornerActive}
963
959
  aria-label=${input.gridAdornerActive ? i18nString(UIStrings.disableGridLanesMode) : i18nString(UIStrings.enableGridLanesMode)}
964
960
  @click=${input.onGridAdornerClick}
@@ -971,7 +967,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
971
967
  role=button
972
968
  tabindex=0
973
969
  .name=${ElementsComponents.AdornerManager.RegisteredAdorners.MEDIA}
974
- jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.MEDIA).track({click: true})}
970
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.MEDIA).track({ click: true })}
975
971
  aria-label=${i18nString(UIStrings.openMediaPanel)}
976
972
  @click=${input.onMediaAdornerClick}
977
973
  @keydown=${handleAdornerKeydown(input.onMediaAdornerClick)}
@@ -986,7 +982,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
986
982
  toggleable=true
987
983
  tabindex=0
988
984
  .name=${ElementsComponents.AdornerManager.RegisteredAdorners.POPOVER}
989
- jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.POPOVER).track({click: true})}
985
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.POPOVER).track({ click: true })}
990
986
  active=${input.popoverAdornerActive}
991
987
  aria-label=${input.popoverAdornerActive ? i18nString(UIStrings.stopForceOpenPopover) : i18nString(UIStrings.forceOpenPopover)}
992
988
  @click=${input.onPopoverAdornerClick}
@@ -999,7 +995,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
999
995
  role=button
1000
996
  tabindex=0
1001
997
  .name=${ElementsComponents.AdornerManager.RegisteredAdorners.TOP_LAYER}
1002
- jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.TOP_LAYER).track({click: true})}
998
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.TOP_LAYER).track({ click: true })}
1003
999
  aria-label=${i18nString(UIStrings.reveal)}
1004
1000
  @click=${input.onTopLayerAdornerClick}
1005
1001
  @keydown=${handleAdornerKeydown(input.onTopLayerAdornerClick)}
@@ -1011,7 +1007,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
1011
1007
  ${input.showStartingStyleAdorner ? html`<devtools-adorner
1012
1008
  class="starting-style"
1013
1009
  .name=${ElementsComponents.AdornerManager.RegisteredAdorners.STARTING_STYLE}
1014
- jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.STARTING_STYLE).track({click: true})}
1010
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.STARTING_STYLE).track({ click: true })}
1015
1011
  active=${input.startingStyleAdornerActive}
1016
1012
  toggleable=true
1017
1013
  aria-label=${input.startingStyleAdornerActive ? i18nString(UIStrings.disableStartingStyle) : i18nString(UIStrings.enableStartingStyle)}
@@ -1023,7 +1019,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
1023
1019
  ${input.showScrollAdorner ? html`<devtools-adorner
1024
1020
  class="scroll"
1025
1021
  .name=${ElementsComponents.AdornerManager.RegisteredAdorners.SCROLL}
1026
- jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.SCROLL).track({click: true})}
1022
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.SCROLL).track({ click: true })}
1027
1023
  aria-label=${i18nString(UIStrings.elementHasScrollableOverflow)}
1028
1024
  ${adornerRef()}>
1029
1025
  <span>${ElementsComponents.AdornerManager.RegisteredAdorners.SCROLL}</span>
@@ -1033,7 +1029,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
1033
1029
  role=button
1034
1030
  tabindex=0
1035
1031
  .name=${ElementsComponents.AdornerManager.RegisteredAdorners.SLOT}
1036
- jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.SLOT).track({click: true})}
1032
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.SLOT).track({ click: true })}
1037
1033
  @click=${input.onSlotAdornerClick}
1038
1034
  @mousedown=${(e: Event) => e.stopPropagation()}
1039
1035
  ${adornerRef()}>
@@ -1045,7 +1041,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
1045
1041
  ${input.showScrollSnapAdorner ? html`<devtools-adorner
1046
1042
  class="scroll-snap"
1047
1043
  .name=${ElementsComponents.AdornerManager.RegisteredAdorners.SCROLL_SNAP}
1048
- jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.SCROLL_SNAP).track({click: true})}
1044
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.SCROLL_SNAP).track({ click: true })}
1049
1045
  active=${input.scrollSnapAdornerActive}
1050
1046
  toggleable=true
1051
1047
  aria-label=${input.scrollSnapAdornerActive ? i18nString(UIStrings.disableScrollSnap) : i18nString(UIStrings.enableScrollSnap)}
@@ -1056,7 +1052,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
1056
1052
  </devtools-adorner>` : nothing}
1057
1053
  </div>`: nothing}
1058
1054
  ${input.isSelected ? html`
1059
- <span class="selected-hint" title=${i18nString(UIStrings.useSInTheConsoleToReferToThis, {PH1: '$0'})} aria-hidden="true"></span>
1055
+ <span class="selected-hint" title=${i18nString(UIStrings.useSInTheConsoleToReferToThis, { PH1: '$0' })} aria-hidden="true"></span>
1060
1056
  ` : nothing}
1061
1057
  ${input.showAiButton ? html`
1062
1058
  <span class="ai-button-container">
@@ -1261,7 +1257,8 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1261
1257
  showSlotAdorner: Boolean(this.nodeInternal.assignedSlot) && !this.isClosingTag(),
1262
1258
  showStartingStyleAdorner: this.nodeInternal.affectedByStartingStyles() && !this.isClosingTag(),
1263
1259
  startingStyleAdornerActive: this.#startingStyleAdornerActive,
1264
- onStartingStyleAdornerClick: (event: Event) => this.#onStartingStyleAdornerClick(event),
1260
+ onStartingStyleAdornerClick:
1261
+ this.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onStartingStyleAdornerClick(event),
1265
1262
  onSlotAdornerClick: () => {
1266
1263
  if (this.nodeInternal.assignedSlot) {
1267
1264
  const deferredNode = this.nodeInternal.assignedSlot.deferredNode;
@@ -1271,25 +1268,32 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1271
1268
  }
1272
1269
  },
1273
1270
  topLayerIndex: this.node().topLayerIndex(),
1274
- onViewSourceAdornerClick: this.revealHTMLInSources.bind(this),
1271
+ onViewSourceAdornerClick: this.treeOutline?.disableEdits ? () => {} : this.revealHTMLInSources.bind(this),
1275
1272
  onGutterClick: this.showContextMenu.bind(this),
1276
- onContainerAdornerClick: (event: Event) => this.#onContainerAdornerClick(event),
1277
- onFlexAdornerClick: (event: Event) => this.#onFlexAdornerClick(event),
1278
- onGridAdornerClick: (event: Event) => this.#onGridAdornerClick(event),
1279
- onMediaAdornerClick: (event: Event) => this.#onMediaAdornerClick(event),
1280
- onPopoverAdornerClick: (event: Event) => this.#onPopoverAdornerClick(event),
1281
- onScrollSnapAdornerClick: (event: Event) => this.#onScrollSnapAdornerClick(event),
1282
- onTopLayerAdornerClick: () => {
1283
- if (!this.treeOutline) {
1284
- return;
1285
- }
1286
- this.treeOutline.revealInTopLayer(this.node());
1287
- },
1273
+ onContainerAdornerClick:
1274
+ this.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onContainerAdornerClick(event),
1275
+ onFlexAdornerClick: this.treeOutline?.disableEdits ? () => {} :
1276
+ (event: Event) => this.#onFlexAdornerClick(event),
1277
+ onGridAdornerClick: this.treeOutline?.disableEdits ? () => {} :
1278
+ (event: Event) => this.#onGridAdornerClick(event),
1279
+ onMediaAdornerClick: this.treeOutline?.disableEdits ? () => {} :
1280
+ (event: Event) => this.#onMediaAdornerClick(event),
1281
+ onPopoverAdornerClick: this.treeOutline?.disableEdits ? () => {} :
1282
+ (event: Event) => this.#onPopoverAdornerClick(event),
1283
+ onScrollSnapAdornerClick:
1284
+ this.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onScrollSnapAdornerClick(event),
1285
+ onTopLayerAdornerClick: this.treeOutline?.disableEdits ? () => {} :
1286
+ () => {
1287
+ if (!this.treeOutline) {
1288
+ return;
1289
+ }
1290
+ this.treeOutline.revealInTopLayer(this.node());
1291
+ },
1288
1292
  isHovered: this.#hovered,
1289
1293
  isSelected: this.selected,
1290
1294
  showAiButton: Boolean(this.#hovered || this.selected) && this.node().nodeType() === Node.ELEMENT_NODE &&
1291
- UI.ActionRegistry.ActionRegistry.instance().hasAction('freestyler.elements-floating-button'),
1292
- aiButtonTitle: UI.ActionRegistry.ActionRegistry.instance().hasAction('freestyler.elements-floating-button') ?
1295
+ this.isAiButtonEnabled() && (this.treeOutline as ElementsTreeOutline)?.showAIButton,
1296
+ aiButtonTitle: this.isAiButtonEnabled() ?
1293
1297
  UI.ActionRegistry.ActionRegistry.instance().getAction('freestyler.elements-floating-button').title() :
1294
1298
  undefined,
1295
1299
  onAiButtonClick: (ev: Event) => {
@@ -1893,6 +1897,10 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1893
1897
  {jslogContext: 'scroll-into-view'});
1894
1898
  }
1895
1899
 
1900
+ private isAiButtonEnabled(): boolean {
1901
+ return UI.ActionRegistry.ActionRegistry.instance().hasAction('freestyler.elements-floating-button');
1902
+ }
1903
+
1896
1904
  async populateTextContextMenu(contextMenu: UI.ContextMenu.ContextMenu, textNode: Element): Promise<void> {
1897
1905
  if (!this.editing) {
1898
1906
  contextMenu.editSection().appendItem(
@@ -90,6 +90,12 @@ interface ViewInput {
90
90
  omitRootDOMNode: boolean;
91
91
  selectEnabled: boolean;
92
92
  hideGutter: boolean;
93
+ maxTreeDepth?: number;
94
+ enableContextMenu?: boolean;
95
+ showComments?: boolean;
96
+ showAIButton?: boolean;
97
+ disableEdits?: boolean;
98
+ expandRoot?: boolean;
93
99
  visibleWidth?: number;
94
100
  visible?: boolean;
95
101
  wrap: boolean;
@@ -119,7 +125,9 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
119
125
  // FIXME: this is basically a ref to existing imperative
120
126
  // implementation. Once this is declarative the ref should not be
121
127
  // needed.
122
- output.elementsTreeOutline = new ElementsTreeOutline(input.omitRootDOMNode, input.selectEnabled, input.hideGutter);
128
+ output.elementsTreeOutline = new ElementsTreeOutline(
129
+ input.omitRootDOMNode, input.selectEnabled, input.hideGutter, input.maxTreeDepth, input.enableContextMenu,
130
+ input.showComments, input.showAIButton, input.disableEdits, input.expandRoot);
123
131
  output.elementsTreeOutline.addEventListener(
124
132
  ElementsTreeOutline.Events.SelectedNodeChanged, input.onSelectedNodeChanged, this);
125
133
  output.elementsTreeOutline.addEventListener(
@@ -128,6 +136,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
128
136
  output.elementsTreeOutline.addEventListener(UI.TreeOutline.Events.ElementCollapsed, input.onElementCollapsed, this);
129
137
  target.appendChild(output.elementsTreeOutline.element);
130
138
  }
139
+
131
140
  if (input.visibleWidth !== undefined) {
132
141
  output.elementsTreeOutline.setVisibleWidth(input.visibleWidth);
133
142
  }
@@ -209,6 +218,11 @@ export class DOMTreeWidget extends UI.Widget.Widget {
209
218
  onElementExpanded: () => void = () => {};
210
219
  onElementCollapsed: () => void = () => {};
211
220
 
221
+ #maxTreeDepth?: number;
222
+ #enableContextMenu = true;
223
+ #showComments = true;
224
+ #showAIButton = true;
225
+ #disableEdits = false;
212
226
  #visible = false;
213
227
  #visibleWidth?: number;
214
228
  #wrap = false;
@@ -232,6 +246,51 @@ export class DOMTreeWidget extends UI.Widget.Widget {
232
246
  return this.#viewOutput.elementsTreeOutline?.rootDOMNode ?? null;
233
247
  }
234
248
 
249
+ get maxTreeDepth(): number|undefined {
250
+ return this.#maxTreeDepth;
251
+ }
252
+
253
+ set maxTreeDepth(maxTreeDepth: number|undefined) {
254
+ this.#maxTreeDepth = maxTreeDepth;
255
+ this.performUpdate();
256
+ }
257
+
258
+ get enableContextMenu(): boolean {
259
+ return this.#enableContextMenu;
260
+ }
261
+
262
+ set enableContextMenu(enableContextMenu: boolean) {
263
+ this.#enableContextMenu = enableContextMenu;
264
+ this.performUpdate();
265
+ }
266
+
267
+ get showComments(): boolean {
268
+ return this.#showComments;
269
+ }
270
+
271
+ set showComments(showComments: boolean) {
272
+ this.#showComments = showComments;
273
+ this.performUpdate();
274
+ }
275
+
276
+ get showAIButton(): boolean {
277
+ return this.#showAIButton;
278
+ }
279
+
280
+ set showAIButton(showAIButton: boolean) {
281
+ this.#showAIButton = showAIButton;
282
+ this.performUpdate();
283
+ }
284
+
285
+ get disableEdits(): boolean {
286
+ return this.#disableEdits;
287
+ }
288
+
289
+ set disableEdits(disableEdits: boolean) {
290
+ this.#disableEdits = disableEdits;
291
+ this.performUpdate();
292
+ }
293
+
235
294
  #currentHighlightedNode: SDK.DOMModel.DOMNode|null = null;
236
295
 
237
296
  #view: View;
@@ -323,6 +382,11 @@ export class DOMTreeWidget extends UI.Widget.Widget {
323
382
  omitRootDOMNode: this.omitRootDOMNode,
324
383
  selectEnabled: this.selectEnabled,
325
384
  hideGutter: this.hideGutter,
385
+ maxTreeDepth: this.#maxTreeDepth,
386
+ enableContextMenu: this.#enableContextMenu,
387
+ showComments: this.#showComments,
388
+ showAIButton: this.#showAIButton,
389
+ disableEdits: this.#disableEdits,
326
390
  visibleWidth: this.#visibleWidth,
327
391
  visible: this.#visible,
328
392
  wrap: this.#wrap,
@@ -501,8 +565,17 @@ export class ElementsTreeOutline extends
501
565
  #issuesManager?: IssuesManager.IssuesManager.IssuesManager;
502
566
  #popupHelper?: UI.PopoverHelper.PopoverHelper;
503
567
  #nodeElementToIssues = new Map<Element, IssuesManager.Issue.Issue[]>();
504
-
505
- constructor(omitRootDOMNode?: boolean, selectEnabled?: boolean, hideGutter?: boolean) {
568
+ readonly maxTreeDepth?: number;
569
+ readonly enableContextMenu: boolean;
570
+ readonly showComments: boolean;
571
+ readonly showAIButton: boolean;
572
+ readonly disableEdits: boolean;
573
+ readonly expandRoot: boolean;
574
+
575
+ constructor(
576
+ omitRootDOMNode?: boolean, selectEnabled?: boolean, hideGutter?: boolean, maxTreeDepth?: number,
577
+ enableContextMenu?: boolean, showComments?: boolean, showAIButton?: boolean, disableEdits?: boolean,
578
+ expandRoot?: boolean) {
506
579
  super();
507
580
 
508
581
  this.#issuesManager = IssuesManager.IssuesManager.IssuesManager.instance();
@@ -516,26 +589,35 @@ export class ElementsTreeOutline extends
516
589
 
517
590
  this.elementInternal = this.element;
518
591
  this.elementInternal.classList.add('elements-tree-outline', 'source-code');
519
- if (hideGutter) {
520
- this.elementInternal.classList.add('elements-hide-gutter');
521
- }
592
+ this.maxTreeDepth = maxTreeDepth;
593
+ this.enableContextMenu = enableContextMenu ?? true;
594
+ this.showComments = showComments ?? true;
595
+ this.showAIButton = showAIButton ?? true;
596
+ this.disableEdits = disableEdits ?? false;
597
+ this.expandRoot = expandRoot ?? false;
598
+ this.elementInternal.classList.toggle('elements-hide-gutter', hideGutter);
522
599
  UI.ARIAUtils.setLabel(this.elementInternal, i18nString(UIStrings.pageDom));
523
600
  this.elementInternal.addEventListener('focusout', this.onfocusout.bind(this), false);
524
601
  this.elementInternal.addEventListener('mousedown', this.onmousedown.bind(this), false);
525
602
  this.elementInternal.addEventListener('mousemove', this.onmousemove.bind(this), false);
526
603
  this.elementInternal.addEventListener('mouseleave', this.onmouseleave.bind(this), false);
527
- this.elementInternal.addEventListener('dragstart', this.ondragstart.bind(this), false);
528
- this.elementInternal.addEventListener('dragover', this.ondragover.bind(this), false);
529
- this.elementInternal.addEventListener('dragleave', this.ondragleave.bind(this), false);
530
- this.elementInternal.addEventListener('drop', this.ondrop.bind(this), false);
531
- this.elementInternal.addEventListener('dragend', this.ondragend.bind(this), false);
532
- this.elementInternal.addEventListener('contextmenu', this.contextMenuEventFired.bind(this), false);
533
- this.elementInternal.addEventListener('clipboard-beforecopy', this.onBeforeCopy.bind(this), false);
534
- this.elementInternal.addEventListener('clipboard-copy', this.onCopyOrCut.bind(this, false), false);
535
- this.elementInternal.addEventListener('clipboard-cut', this.onCopyOrCut.bind(this, true), false);
536
- this.elementInternal.addEventListener('clipboard-paste', this.onPaste.bind(this), false);
537
604
  this.elementInternal.addEventListener('keydown', this.onKeyDown.bind(this), false);
538
605
 
606
+ if (!this.disableEdits) {
607
+ this.elementInternal.addEventListener('dragstart', this.ondragstart.bind(this), false);
608
+ this.elementInternal.addEventListener('dragover', this.ondragover.bind(this), false);
609
+ this.elementInternal.addEventListener('dragleave', this.ondragleave.bind(this), false);
610
+ this.elementInternal.addEventListener('drop', this.ondrop.bind(this), false);
611
+ this.elementInternal.addEventListener('dragend', this.ondragend.bind(this), false);
612
+ this.elementInternal.addEventListener('clipboard-beforecopy', this.onBeforeCopy.bind(this), false);
613
+ this.elementInternal.addEventListener('clipboard-copy', this.onCopyOrCut.bind(this, false), false);
614
+ this.elementInternal.addEventListener('clipboard-cut', this.onCopyOrCut.bind(this, true), false);
615
+ this.elementInternal.addEventListener('clipboard-paste', this.onPaste.bind(this), false);
616
+ }
617
+ if (this.enableContextMenu) {
618
+ this.elementInternal.addEventListener('contextmenu', this.contextMenuEventFired.bind(this), false);
619
+ }
620
+
539
621
  outlineDisclosureElement.appendChild(this.elementInternal);
540
622
  this.element = shadowContainer;
541
623
  this.contentElement.setAttribute('jslog', `${VisualLogging.tree('elements')}`);
@@ -571,9 +653,16 @@ export class ElementsTreeOutline extends
571
653
  this.treeElementsBeingUpdated = new Set();
572
654
 
573
655
  this.decoratorExtensions = null;
574
-
575
- this.showHTMLCommentsSetting = Common.Settings.Settings.instance().moduleSetting('show-html-comments');
576
- this.showHTMLCommentsSetting.addChangeListener(this.onShowHTMLCommentsChange.bind(this));
656
+ if (this.showComments) {
657
+ this.showHTMLCommentsSetting = Common.Settings.Settings.instance().moduleSetting('show-html-comments');
658
+ this.showHTMLCommentsSetting.addChangeListener(this.onShowHTMLCommentsChange.bind(this));
659
+ } else {
660
+ this.showHTMLCommentsSetting = {
661
+ get: () => false,
662
+ addChangeListener: () => {},
663
+ removeChangeListener: () => {},
664
+ } as unknown as Common.Settings.Setting<boolean>;
665
+ }
577
666
  this.setUseLightSelectionColor(true);
578
667
  // TODO(changhaohan): refactor the popover to use tooltip component.
579
668
  this.#popupHelper = new UI.PopoverHelper.PopoverHelper(this.elementInternal, event => {
@@ -595,19 +684,20 @@ export class ElementsTreeOutline extends
595
684
  render(html`
596
685
  <div class="squiggles-content">
597
686
  ${issues.map(issue => {
598
- const elementIssueDetails = getElementIssueDetails(issue);
599
- if (!elementIssueDetails) {
600
- // This shouldn't happen, but add this if check to pass ts check.
601
- return nothing;
602
- }
603
- const issueKindIconName = IssueCounter.IssueCounter.getIssueKindIconName(issue.getKind());
604
- const openIssueEvent = (): Promise<void> => Common.Revealer.reveal(issue);
605
- return html`
687
+ const elementIssueDetails = getElementIssueDetails(issue);
688
+ if (!elementIssueDetails) {
689
+ // This shouldn't happen, but add this if check to pass ts check.
690
+ return nothing;
691
+ }
692
+ const issueKindIconName = IssueCounter.IssueCounter.getIssueKindIconName(issue.getKind());
693
+ const openIssueEvent = (): Promise<void> => Common.Revealer.reveal(issue);
694
+ return html`
606
695
  <div class="squiggles-content-item">
607
696
  <devtools-icon .name=${issueKindIconName} @click=${openIssueEvent}></devtools-icon>
608
697
  <devtools-link class="link" @click=${openIssueEvent}>${i18nString(UIStrings.viewIssue)}</devtools-link>
609
698
  <span>${elementIssueDetails.tooltip}</span>
610
- </div>`;})}
699
+ </div>`;
700
+ })}
611
701
  </div>`, popover.contentElement);
612
702
  // clang-format on
613
703
  return true;
@@ -958,6 +1048,9 @@ export class ElementsTreeOutline extends
958
1048
  if (this.includeRootDOMNode) {
959
1049
  const treeElement = this.createElementTreeElement(this.rootDOMNode);
960
1050
  this.appendChild(treeElement);
1051
+ if (this.expandRoot) {
1052
+ treeElement.expand();
1053
+ }
961
1054
  } else {
962
1055
  // FIXME: this could use findTreeElement to reuse a tree element if it already exists
963
1056
  const children = this.visibleChildren(this.rootDOMNode);
@@ -1774,6 +1867,31 @@ export class ElementsTreeOutline extends
1774
1867
  }
1775
1868
  }
1776
1869
 
1870
+ private isMaxDepthReached(node: SDK.DOMModel.DOMNode): boolean {
1871
+ if (this.maxTreeDepth === undefined || this.maxTreeDepth === Infinity) {
1872
+ return false;
1873
+ }
1874
+ // Allow ShadowRoots and Documents to expand one more level.
1875
+ if (node.nodeType() === Node.DOCUMENT_NODE || node.isShadowRoot()) {
1876
+ return false;
1877
+ }
1878
+ const maxDepth = this.maxTreeDepth;
1879
+ let depth = 0;
1880
+ let current: SDK.DOMModel.DOMNode|null = node;
1881
+ const rootNode = this.rootDOMNode;
1882
+ while (current && current !== rootNode) {
1883
+ depth++;
1884
+ current = current.parentNode;
1885
+ }
1886
+ if (this.includeRootDOMNode) {
1887
+ depth++;
1888
+ }
1889
+ if (depth >= maxDepth) {
1890
+ return true;
1891
+ }
1892
+ return false;
1893
+ }
1894
+
1777
1895
  private createElementTreeElement(node: SDK.DOMModel.DOMNode|SDK.DOMModel.AdoptedStyleSheet[], isClosingTag?: boolean):
1778
1896
  UI.TreeOutline.TreeElement {
1779
1897
  if (node instanceof Array) {
@@ -1870,6 +1988,9 @@ export class ElementsTreeOutline extends
1870
1988
  }
1871
1989
 
1872
1990
  private hasVisibleChildren(node: SDK.DOMModel.DOMNode): boolean {
1991
+ if (this.isMaxDepthReached(node)) {
1992
+ return false;
1993
+ }
1873
1994
  if (node.isIframe()) {
1874
1995
  return true;
1875
1996
  }
@@ -77,6 +77,7 @@ const UIStrings = {
77
77
  } as const;
78
78
  const str_ = i18n.i18n.registerUIStrings('panels/elements/EventListenersWidget.ts', UIStrings);
79
79
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
80
+ const {widget} = UI.Widget;
80
81
  let eventListenersWidgetInstance: EventListenersWidget;
81
82
 
82
83
  interface ViewInput {
@@ -123,11 +124,11 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
123
124
  ${i18nString(UIStrings.frameworkListeners)}
124
125
  </devtools-checkbox>
125
126
  </devtools-toolbar>
126
- <devtools-widget .widgetConfig=${UI.Widget.widgetConfig(EventListeners.EventListenersView.EventListenersView, {
127
+ ${widget(EventListeners.EventListenersView.EventListenersView, {
127
128
  changeCallback: input.onEventListenersViewChange,
128
129
  objects: input.eventListenerObjects,
129
130
  filter: input.filter,
130
- })}></devtools-widget>
131
+ })}
131
132
  </div>`, target);
132
133
  // clang-format on
133
134
  };
@@ -63,6 +63,7 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
63
63
  #swatchPopoverHelper = new InlineEditor.SwatchPopoverHelper.SwatchPopoverHelper();
64
64
  #computedStyleModelInternal = new ComputedStyle.ComputedStyleModel.ComputedStyleModel();
65
65
  #view: View;
66
+ #filter: RegExp|null = null;
66
67
 
67
68
  constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
68
69
  super(element, {useShadowDom: true});
@@ -84,6 +85,8 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
84
85
  return;
85
86
  }
86
87
 
88
+ this.node()?.domModel().cssModel().discardCachedMatchedCascade();
89
+ await this.#updateSections();
87
90
  this.requestUpdate();
88
91
  }
89
92
 
@@ -127,17 +130,15 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
127
130
  this.sectionByElement.set(section.element, section);
128
131
  }
129
132
  this.#sections = newSections;
133
+ this.#updateFilter();
130
134
  this.swatchPopoverHelper().reposition();
131
135
  }
132
136
 
133
137
  override async performUpdate(): Promise<void> {
134
138
  this.hideAllPopovers();
135
- this.node()?.domModel().cssModel().discardCachedMatchedCascade();
136
-
137
- await this.#updateSections();
138
139
 
139
140
  const viewInput: ViewInput = {
140
- sections: this.#sections,
141
+ sections: this.#sections.filter(section => !section.isHidden()),
141
142
  };
142
143
  this.#view(viewInput, undefined, this.contentElement);
143
144
  this.#onUpdateFinished();
@@ -147,6 +148,12 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
147
148
  this.dispatchEventToListeners(Events.STYLES_UPDATE_COMPLETED);
148
149
  }
149
150
 
151
+ #updateFilter(): void {
152
+ for (const section of this.#sections) {
153
+ section.updateFilter();
154
+ }
155
+ }
156
+
150
157
  swatchPopoverHelper(): InlineEditor.SwatchPopoverHelper.SwatchPopoverHelper {
151
158
  return this.#swatchPopoverHelper;
152
159
  }
@@ -157,6 +164,11 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
157
164
  return;
158
165
  }
159
166
  this.#computedStyleModelInternal.node = node;
167
+ }
168
+
169
+ set filter(regex: RegExp|null) {
170
+ this.#filter = regex;
171
+ this.#updateFilter();
160
172
  this.requestUpdate();
161
173
  }
162
174
 
@@ -195,7 +207,7 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
195
207
  }
196
208
 
197
209
  filterRegex(): RegExp|null {
198
- return null;
210
+ return this.#filter;
199
211
  }
200
212
 
201
213
  setEditingStyle(editing: boolean): void {
@@ -207,7 +219,10 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
207
219
  }
208
220
 
209
221
  forceUpdate(): void {
210
- this.requestUpdate();
222
+ this.node()?.domModel().cssModel().discardCachedMatchedCascade();
223
+ void this.#updateSections().then(() => {
224
+ this.requestUpdate();
225
+ });
211
226
  }
212
227
 
213
228
  hideAllPopovers(): void {