chrome-devtools-frontend 1.0.1597448 → 1.0.1598808

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 (143) hide show
  1. package/docs/ui_engineering.md +6 -6
  2. package/front_end/core/host/AidaClient.ts +6 -0
  3. package/front_end/core/sdk/CPUThrottlingManager.ts +5 -1
  4. package/front_end/core/sdk/CSSMatchedStyles.ts +2 -0
  5. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +28 -0
  6. package/front_end/models/ai_assistance/AiConversation.ts +40 -22
  7. package/front_end/models/ai_assistance/ChangeManager.ts +16 -0
  8. package/front_end/models/ai_assistance/ExtensionScope.ts +11 -3
  9. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +127 -0
  10. package/front_end/models/ai_assistance/agents/AiAgent.ts +35 -6
  11. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +1 -1
  12. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +11 -8
  13. package/front_end/models/ai_assistance/agents/ConversationSummaryAgent.ts +109 -0
  14. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +30 -1
  15. package/front_end/models/ai_assistance/agents/StylingAgent.ts +34 -4
  16. package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
  17. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +27 -0
  18. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +21 -0
  19. package/front_end/models/trace/Processor.ts +1 -0
  20. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -0
  21. package/front_end/models/trace/insights/CharacterSet.ts +172 -0
  22. package/front_end/models/trace/insights/Models.ts +1 -0
  23. package/front_end/models/trace/insights/types.ts +1 -0
  24. package/front_end/models/trace/types/TraceEvents.ts +17 -0
  25. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +22 -12
  26. package/front_end/panels/ai_assistance/PatchWidget.ts +1 -1
  27. package/front_end/panels/ai_assistance/components/ChatMessage.ts +131 -63
  28. package/front_end/panels/ai_assistance/components/ChatView.ts +1 -1
  29. package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +18 -9
  30. package/front_end/panels/ai_assistance/components/chatMessage.css +11 -0
  31. package/front_end/panels/application/AppManifestView.ts +4 -5
  32. package/front_end/panels/application/CookieItemsView.ts +9 -15
  33. package/front_end/panels/application/DeviceBoundSessionsView.ts +20 -26
  34. package/front_end/panels/application/FrameDetailsView.ts +10 -16
  35. package/front_end/panels/application/OriginTrialTreeView.ts +2 -3
  36. package/front_end/panels/application/ReportingApiView.ts +14 -18
  37. package/front_end/panels/application/components/BackForwardCacheView.ts +3 -3
  38. package/front_end/panels/application/preloading/PreloadingView.ts +18 -3
  39. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +2 -3
  40. package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +3 -2
  41. package/front_end/panels/changes/ChangesView.ts +13 -15
  42. package/front_end/panels/console/ConsolePinPane.ts +3 -3
  43. package/front_end/panels/coverage/CoverageListView.ts +1 -1
  44. package/front_end/panels/coverage/CoverageView.ts +4 -4
  45. package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +3 -3
  46. package/front_end/panels/css_overview/CSSOverviewPanel.ts +11 -15
  47. package/front_end/panels/developer_resources/DeveloperResourcesView.ts +3 -5
  48. package/front_end/panels/elements/ElementsTreeOutline.ts +34 -8
  49. package/front_end/panels/elements/EventListenersWidget.ts +3 -2
  50. package/front_end/panels/elements/StandaloneStylesContainer.ts +21 -6
  51. package/front_end/panels/elements/StylePropertiesSection.ts +129 -1
  52. package/front_end/panels/elements/StylePropertyHighlighter.ts +3 -0
  53. package/front_end/panels/elements/StylePropertyTreeElement.ts +49 -4
  54. package/front_end/panels/elements/stylesSidebarPane.css +34 -0
  55. package/front_end/panels/issues/AffectedSelectivePermissionsInterventionView.ts +3 -5
  56. package/front_end/panels/layer_viewer/LayerDetailsView.ts +2 -1
  57. package/front_end/panels/layer_viewer/Layers3DView.ts +5 -4
  58. package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +5 -6
  59. package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +6 -11
  60. package/front_end/panels/network/RequestConditionsDrawer.ts +4 -4
  61. package/front_end/panels/network/RequestCookiesView.ts +5 -6
  62. package/front_end/panels/network/RequestHeadersView.ts +4 -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/performance_monitor/PerformanceMonitor.ts +2 -2
  66. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +5 -6
  67. package/front_end/panels/recorder/components/RecordingView.ts +31 -36
  68. package/front_end/panels/recorder/components/StepEditor.ts +6 -7
  69. package/front_end/panels/recorder/components/StepView.ts +2 -1
  70. package/front_end/panels/search/SearchView.ts +3 -4
  71. package/front_end/panels/settings/WorkspaceSettingsTab.ts +2 -5
  72. package/front_end/panels/timeline/TimelineDetailsView.ts +8 -6
  73. package/front_end/panels/timeline/components/LiveMetricsView.ts +5 -8
  74. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +2 -7
  75. package/front_end/panels/timeline/components/insights/Cache.ts +8 -10
  76. package/front_end/panels/timeline/components/insights/CharacterSet.ts +34 -0
  77. package/front_end/panels/timeline/components/insights/DOMSize.ts +16 -20
  78. package/front_end/panels/timeline/components/insights/DocumentLatency.ts +2 -6
  79. package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +3 -4
  80. package/front_end/panels/timeline/components/insights/EventRef.ts +2 -2
  81. package/front_end/panels/timeline/components/insights/FontDisplay.ts +3 -4
  82. package/front_end/panels/timeline/components/insights/ForcedReflow.ts +5 -7
  83. package/front_end/panels/timeline/components/insights/INPBreakdown.ts +3 -4
  84. package/front_end/panels/timeline/components/insights/ImageDelivery.ts +3 -4
  85. package/front_end/panels/timeline/components/insights/ImageRef.ts +2 -4
  86. package/front_end/panels/timeline/components/insights/InsightRenderer.ts +2 -0
  87. package/front_end/panels/timeline/components/insights/LCPBreakdown.ts +5 -7
  88. package/front_end/panels/timeline/components/insights/LCPDiscovery.ts +2 -4
  89. package/front_end/panels/timeline/components/insights/LegacyJavaScript.ts +3 -4
  90. package/front_end/panels/timeline/components/insights/ModernHTTP.ts +3 -4
  91. package/front_end/panels/timeline/components/insights/NetworkDependencyTree.ts +7 -11
  92. package/front_end/panels/timeline/components/insights/NodeLink.ts +2 -4
  93. package/front_end/panels/timeline/components/insights/RenderBlocking.ts +3 -4
  94. package/front_end/panels/timeline/components/insights/SlowCSSSelector.ts +7 -10
  95. package/front_end/panels/timeline/components/insights/ThirdParties.ts +5 -7
  96. package/front_end/panels/timeline/components/insights/insights.ts +2 -0
  97. package/front_end/panels/web_audio/WebAudioView.ts +3 -4
  98. package/front_end/panels/webauthn/WebauthnPane.ts +2 -2
  99. package/front_end/third_party/chromium/README.chromium +1 -1
  100. package/front_end/third_party/puppeteer/README.chromium +2 -2
  101. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Realm.js +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Realm.js.map +1 -1
  103. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.d.ts +4 -0
  104. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.d.ts.map +1 -1
  105. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.js +13 -0
  106. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/util.js.map +1 -1
  107. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  108. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
  109. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
  110. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  112. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  113. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  114. package/front_end/third_party/puppeteer/package/lib/cjs/third_party/mitt/mitt.js +2 -2
  115. package/front_end/third_party/puppeteer/package/lib/cjs/third_party/parsel-js/parsel-js.js +1 -1
  116. package/front_end/third_party/puppeteer/package/lib/cjs/third_party/rxjs/rxjs.js +446 -446
  117. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +166 -167
  118. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Realm.js +2 -2
  119. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Realm.js.map +1 -1
  120. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.d.ts +4 -0
  121. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.d.ts.map +1 -1
  122. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.js +12 -0
  123. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/util.js.map +1 -1
  124. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
  125. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
  126. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  128. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  129. package/front_end/third_party/puppeteer/package/lib/esm/third_party/mitt/mitt.js +1 -1
  130. package/front_end/third_party/puppeteer/package/lib/esm/third_party/parsel-js/parsel-js.js +1 -1
  131. package/front_end/third_party/puppeteer/package/lib/esm/third_party/rxjs/rxjs.js +97 -97
  132. package/front_end/third_party/puppeteer/package/package.json +1 -1
  133. package/front_end/third_party/puppeteer/package/src/bidi/Realm.ts +2 -2
  134. package/front_end/third_party/puppeteer/package/src/bidi/util.ts +17 -0
  135. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  136. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  137. package/front_end/ui/components/settings/SettingCheckbox.ts +2 -0
  138. package/front_end/ui/legacy/Widget.ts +42 -6
  139. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
  140. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +8 -8
  141. package/front_end/ui/visual_logging/Debugging.ts +0 -32
  142. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  143. package/package.json +1 -1
@@ -16,7 +16,7 @@ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
16
16
  import {DeveloperResourcesListView} from './DeveloperResourcesListView.js';
17
17
  import developerResourcesViewStyles from './developerResourcesView.css.js';
18
18
 
19
- const {widgetConfig} = UI.Widget;
19
+ const {widget} = UI.Widget;
20
20
  const {bindToSetting} = UI.UIUtils;
21
21
 
22
22
  const UIStrings = {
@@ -98,14 +98,12 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
98
98
  </devtools-toolbar>
99
99
  </div>
100
100
  <div class="developer-resource-view-results">
101
- <devtools-widget
102
- .widgetConfig=${widgetConfig(DeveloperResourcesListView, {
101
+ ${widget(DeveloperResourcesListView, {
103
102
  items: input.items,
104
103
  selectedItem: input.selectedItem,
105
104
  onSelect: input.onSelect,
106
105
  filters: input.filters
107
- })}>
108
- </devtools-widget>
106
+ })}
109
107
  </div>
110
108
  <div class="developer-resource-view-toolbar-summary">
111
109
  <div class="developer-resource-view-message">
@@ -137,6 +137,13 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
137
137
  target.appendChild(output.elementsTreeOutline.element);
138
138
  }
139
139
 
140
+ output.elementsTreeOutline.maxTreeDepth = input.maxTreeDepth;
141
+ output.elementsTreeOutline.enableContextMenu = input.enableContextMenu ?? true;
142
+ output.elementsTreeOutline.showComments = input.showComments ?? true;
143
+ output.elementsTreeOutline.showAIButton = input.showAIButton ?? true;
144
+ output.elementsTreeOutline.disableEdits = input.disableEdits ?? false;
145
+ output.elementsTreeOutline.expandRoot = input.expandRoot ?? false;
146
+
140
147
  if (input.visibleWidth !== undefined) {
141
148
  output.elementsTreeOutline.setVisibleWidth(input.visibleWidth);
142
149
  }
@@ -223,6 +230,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
223
230
  #showComments = true;
224
231
  #showAIButton = true;
225
232
  #disableEdits = false;
233
+ #expandRoot = false;
226
234
  #visible = false;
227
235
  #visibleWidth?: number;
228
236
  #wrap = false;
@@ -291,6 +299,15 @@ export class DOMTreeWidget extends UI.Widget.Widget {
291
299
  this.performUpdate();
292
300
  }
293
301
 
302
+ get expandRoot(): boolean {
303
+ return this.#expandRoot;
304
+ }
305
+
306
+ set expandRoot(expandRoot: boolean) {
307
+ this.#expandRoot = expandRoot;
308
+ this.performUpdate();
309
+ }
310
+
294
311
  #currentHighlightedNode: SDK.DOMModel.DOMNode|null = null;
295
312
 
296
313
  #view: View;
@@ -347,11 +364,19 @@ export class DOMTreeWidget extends UI.Widget.Widget {
347
364
  this.#viewOutput?.elementsTreeOutline?.highlightNodeAttribute(node, attribute);
348
365
  }
349
366
 
350
- setWordWrap(wrap: boolean): void {
367
+ get wrap(): boolean {
368
+ return this.#wrap;
369
+ }
370
+
371
+ set wrap(wrap: boolean) {
351
372
  this.#wrap = wrap;
352
373
  this.performUpdate();
353
374
  }
354
375
 
376
+ setWordWrap(wrap: boolean): void {
377
+ this.wrap = wrap;
378
+ }
379
+
355
380
  selectedDOMNode(): SDK.DOMModel.DOMNode|null {
356
381
  return this.#viewOutput.elementsTreeOutline?.selectedDOMNode() ?? null;
357
382
  }
@@ -387,6 +412,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
387
412
  showComments: this.#showComments,
388
413
  showAIButton: this.#showAIButton,
389
414
  disableEdits: this.#disableEdits,
415
+ expandRoot: this.#expandRoot,
390
416
  visibleWidth: this.#visibleWidth,
391
417
  visible: this.#visible,
392
418
  wrap: this.#wrap,
@@ -565,12 +591,12 @@ export class ElementsTreeOutline extends
565
591
  #issuesManager?: IssuesManager.IssuesManager.IssuesManager;
566
592
  #popupHelper?: UI.PopoverHelper.PopoverHelper;
567
593
  #nodeElementToIssues = new Map<Element, IssuesManager.Issue.Issue[]>();
568
- readonly maxTreeDepth?: number;
569
- readonly enableContextMenu: boolean;
570
- readonly showComments: boolean;
571
- readonly showAIButton: boolean;
572
- readonly disableEdits: boolean;
573
- readonly expandRoot: boolean;
594
+ maxTreeDepth?: number;
595
+ enableContextMenu: boolean;
596
+ showComments: boolean;
597
+ showAIButton: boolean;
598
+ disableEdits: boolean;
599
+ expandRoot: boolean;
574
600
 
575
601
  constructor(
576
602
  omitRootDOMNode?: boolean, selectEnabled?: boolean, hideGutter?: boolean, maxTreeDepth?: number,
@@ -1388,7 +1414,7 @@ export class ElementsTreeOutline extends
1388
1414
  }
1389
1415
 
1390
1416
  async showContextMenu(treeElement: ElementsTreeElement, event: Event): Promise<void> {
1391
- if (UI.UIUtils.isEditing()) {
1417
+ if (UI.UIUtils.isEditing() || !this.enableContextMenu) {
1392
1418
  return;
1393
1419
  }
1394
1420
 
@@ -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 {
@@ -47,6 +47,7 @@ import * as ComputedStyle from '../../models/computed_style/computed_style.js';
47
47
  import * as TextUtils from '../../models/text_utils/text_utils.js';
48
48
  import * as Buttons from '../../ui/components/buttons/buttons.js';
49
49
  import * as Tooltips from '../../ui/components/tooltips/tooltips.js';
50
+ import {createIcon, type Icon} from '../../ui/kit/kit.js';
50
51
  import type * as Components from '../../ui/legacy/components/utils/utils.js';
51
52
  import * as UI from '../../ui/legacy/legacy.js';
52
53
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
@@ -115,6 +116,14 @@ const UIStrings = {
115
116
  * @example {(0,0,1)} PH1
116
117
  */
117
118
  specificity: 'Specificity: {PH1}',
119
+ /**
120
+ * @description Accessibility label for the button that expands a collapsed CSS rule in the Styles pane.
121
+ */
122
+ expandCollapsedRule: 'Expand collapsed rule',
123
+ /**
124
+ * @description Accessibility label for the button that collapses an expanded CSS rule in the Styles pane.
125
+ */
126
+ collapseExpandedRule: 'Collapse expanded rule',
118
127
  } as const;
119
128
 
120
129
  const str_ = i18n.i18n.registerUIStrings('panels/elements/StylePropertiesSection.ts', UIStrings);
@@ -151,6 +160,8 @@ export class StylePropertiesSection {
151
160
  protected readonly selectorRefElement: HTMLElement;
152
161
  private hoverableSelectorsMode: boolean;
153
162
  #isHidden: boolean;
163
+ #isCollapsed: boolean;
164
+ #collapseIcon: Icon|null = null;
154
165
  protected customPopulateCallback: () => void;
155
166
 
156
167
  nestingLevel = 0;
@@ -228,6 +239,25 @@ export class StylePropertiesSection {
228
239
  const selectorContainer = document.createElement('div');
229
240
  selectorContainer.createChild('span', 'styles-clipboard-only').textContent = indent.repeat(this.nestingLevel);
230
241
  selectorContainer.classList.add('selector-container');
242
+
243
+ // Collapse/expand toggle icon for rules that can be manually toggled.
244
+ this.#collapseIcon = createIcon('triangle-right', 'section-collapse-icon');
245
+ UI.ARIAUtils.markAsButton(this.#collapseIcon);
246
+ UI.ARIAUtils.setControls(this.#collapseIcon, this.propertiesTreeOutline.element);
247
+ this.#collapseIcon.tabIndex = 0;
248
+ this.#collapseIcon.addEventListener('click', (event: Event) => {
249
+ event.consume(true);
250
+ this.#toggleCollapsed();
251
+ });
252
+ this.#collapseIcon.addEventListener('keydown', (event: KeyboardEvent) => {
253
+ if (!Platform.KeyboardUtilities.isEnterOrSpaceKey(event)) {
254
+ return;
255
+ }
256
+ event.consume(true);
257
+ this.#toggleCollapsed();
258
+ });
259
+ selectorContainer.appendChild(this.#collapseIcon);
260
+
231
261
  this.selectorElement = document.createElement('span');
232
262
  UI.ARIAUtils.setLabel(this.selectorElement, i18nString(UIStrings.cssSelector));
233
263
  this.selectorElement.classList.add('selector');
@@ -324,8 +354,10 @@ export class StylePropertiesSection {
324
354
  }
325
355
  this.hoverableSelectorsMode = false;
326
356
  this.#isHidden = false;
357
+ this.#isCollapsed = false;
327
358
  this.markSelectorMatches();
328
359
  this.onpopulate();
360
+ this.#updateCollapsedState();
329
361
 
330
362
  this.stylesContainer.computedStyleModel().addEventListener(
331
363
  ComputedStyle.ComputedStyleModel.Events.CSS_MODEL_CHANGED, this.#onCSSModelChanged, this);
@@ -620,9 +652,18 @@ export class StylePropertiesSection {
620
652
  keyboardEvent.metaKey) {
621
653
  return;
622
654
  }
655
+
656
+ // Only handle section-level edit shortcuts when the event originated from
657
+ // the section itself. Child editors dispatch key events that bubble up to
658
+ // the section, and we must not treat those as section shortcuts.
659
+ const isSectionLevelShortcut = keyboardEvent.target === this.element;
660
+
623
661
  switch (keyboardEvent.key) {
624
662
  case 'Enter':
625
663
  case ' ':
664
+ if (!isSectionLevelShortcut) {
665
+ return;
666
+ }
626
667
  this.startEditingAtFirstPosition();
627
668
  keyboardEvent.consume(true);
628
669
  break;
@@ -634,7 +675,7 @@ export class StylePropertiesSection {
634
675
  break;
635
676
  default:
636
677
  // Filter out non-printable key strokes.
637
- if (keyboardEvent.key.length === 1) {
678
+ if (isSectionLevelShortcut && keyboardEvent.key.length === 1) {
638
679
  this.addNewBlankProperty(0).startEditingName();
639
680
  }
640
681
  break;
@@ -1333,6 +1374,82 @@ export class StylePropertiesSection {
1333
1374
  return this.#isHidden;
1334
1375
  }
1335
1376
 
1377
+ /**
1378
+ * Checks whether the section should be collapsed because it does not
1379
+ * contribute any active styles. A section is collapsed when:
1380
+ * - It has no leading properties (empty rule), OR
1381
+ * - All its leading properties have PropertyState.OVERLOADED
1382
+ *
1383
+ * Sections containing only user-disabled properties are NOT collapsed,
1384
+ * since the user intentionally toggled them off and they should remain visible.
1385
+ */
1386
+ #shouldCollapse(): boolean {
1387
+ const style = this.styleInternal;
1388
+ const properties = style.leadingProperties();
1389
+
1390
+ // Never collapse the element's own inline style section.
1391
+ if (style.type === SDK.CSSStyleDeclaration.Type.Inline) {
1392
+ return false;
1393
+ }
1394
+
1395
+ // Empty rule (e.g. from CSS nesting): collapse.
1396
+ if (properties.length === 0) {
1397
+ return true;
1398
+ }
1399
+
1400
+ // If any property is user-disabled (toggled off via checkbox), do not
1401
+ // collapse. The user deliberately disabled them.
1402
+ const hasDisabledProperty = properties.some(p => p.disabled);
1403
+ if (hasDisabledProperty) {
1404
+ return false;
1405
+ }
1406
+
1407
+ // If every property is OVERLOADED, collapse.
1408
+ const allOverloaded =
1409
+ properties.every(p => this.matchedStyles.propertyState(p) === SDK.CSSMatchedStyles.PropertyState.OVERLOADED);
1410
+ return allOverloaded;
1411
+ }
1412
+
1413
+ #updateCollapsedState(): void {
1414
+ const shouldCollapse = this.#shouldCollapse();
1415
+ // Mark as collapsible so the toggle icon is always shown for
1416
+ // sections that can be collapsed, even after manual expansion.
1417
+ this.element.classList.toggle('collapsible', shouldCollapse);
1418
+ this.#setCollapsed(shouldCollapse);
1419
+ }
1420
+
1421
+ #setCollapsed(collapsed: boolean): void {
1422
+ this.#isCollapsed = collapsed;
1423
+ this.element.classList.toggle('collapsed', collapsed);
1424
+ this.propertiesTreeOutline.element.classList.toggle('hidden', collapsed);
1425
+ if (this.#collapseIcon) {
1426
+ this.#collapseIcon.name = collapsed ? 'triangle-right' : 'triangle-down';
1427
+ UI.ARIAUtils.setExpanded(this.#collapseIcon, !collapsed);
1428
+ UI.ARIAUtils.setLabel(
1429
+ this.#collapseIcon,
1430
+ collapsed ? i18nString(UIStrings.expandCollapsedRule) : i18nString(UIStrings.collapseExpandedRule));
1431
+ }
1432
+ }
1433
+
1434
+ #toggleCollapsed(): void {
1435
+ this.#setCollapsed(!this.#isCollapsed);
1436
+ }
1437
+
1438
+ /**
1439
+ * Expand a collapsed section, e.g. when navigating to a property
1440
+ * via a var() link.
1441
+ */
1442
+ expand(): void {
1443
+ if (!this.#isCollapsed) {
1444
+ return;
1445
+ }
1446
+ this.#setCollapsed(false);
1447
+ }
1448
+
1449
+ isCollapsed(): boolean {
1450
+ return this.#isCollapsed;
1451
+ }
1452
+
1336
1453
  markSelectorMatches(): void {
1337
1454
  const rule = this.styleInternal.parentRule;
1338
1455
  if (!rule || !(rule instanceof SDK.CSSRule.CSSStyleRule)) {
@@ -1395,6 +1512,10 @@ export class StylePropertiesSection {
1395
1512
 
1396
1513
  addNewBlankProperty(index: number|undefined = this.propertiesTreeOutline.rootElement().childCount()):
1397
1514
  StylePropertyTreeElement {
1515
+ if (this.#isCollapsed) {
1516
+ this.expand();
1517
+ }
1518
+
1398
1519
  const property = this.styleInternal.newBlankProperty(index);
1399
1520
  const item = new StylePropertyTreeElement({
1400
1521
  stylesContainer: this.stylesContainer,
@@ -1416,6 +1537,13 @@ export class StylePropertiesSection {
1416
1537
  }
1417
1538
 
1418
1539
  private handleEmptySpaceClick(event: Event): void {
1540
+ // If collapsed, clicking anywhere on the section should expand it.
1541
+ if (this.#isCollapsed) {
1542
+ this.#toggleCollapsed();
1543
+ event.consume(true);
1544
+ return;
1545
+ }
1546
+
1419
1547
  // `this.willCauseCancelEditing` is a hacky way to understand whether we should
1420
1548
  // create a new property or not on empty space click.
1421
1549
  // For empty space clicks, the order of events are:
@@ -24,6 +24,7 @@ export class StylePropertyHighlighter {
24
24
  if (!section) {
25
25
  return;
26
26
  }
27
+ section.expand();
27
28
  section.showAllItems();
28
29
  const populatePromises: Array<Promise<void>> = [];
29
30
  for (let treeElement = section.propertiesTreeOutline.firstChild(); treeElement;
@@ -57,6 +58,7 @@ export class StylePropertyHighlighter {
57
58
  return;
58
59
  }
59
60
  block.expand(true);
61
+ section.expand();
60
62
  section.showAllItems();
61
63
  PanelUtils.highlightElement(section.element);
62
64
  }
@@ -78,6 +80,7 @@ export class StylePropertyHighlighter {
78
80
  continue;
79
81
  }
80
82
  block?.expand(true);
83
+ section.expand();
81
84
  section.showAllItems();
82
85
  const treeElement = this.findTreeElementFromSection(
83
86
  treeElement => treeElement.property.name === propertyName && !treeElement.overloaded(), section);
@@ -1024,6 +1024,46 @@ export class ColorMixRenderer extends rendererBase(SDK.CSSPropertyParserMatchers
1024
1024
  }
1025
1025
  }
1026
1026
 
1027
+ // clang-format off
1028
+ export class ContrastColorRenderer extends rendererBase(SDK.CSSPropertyParserMatchers.ContrastColorMatch) {
1029
+ // clang-format on
1030
+ readonly #treeElement: StylePropertyTreeElement|null;
1031
+ readonly #stylesContainer: StylesContainer;
1032
+ constructor(stylesContainer: StylesContainer, treeElement: StylePropertyTreeElement|null) {
1033
+ super();
1034
+ this.#treeElement = treeElement;
1035
+ this.#stylesContainer = stylesContainer;
1036
+ }
1037
+
1038
+ override render(match: SDK.CSSPropertyParserMatchers.ContrastColorMatch, context: RenderingContext): Node[] {
1039
+ const content = document.createElement('span');
1040
+ content.appendChild(document.createTextNode('contrast-color('));
1041
+ const param = content.appendChild(document.createElement('span'));
1042
+ content.appendChild(document.createTextNode(')'));
1043
+ Renderer.renderInto(match.color, context, param);
1044
+
1045
+ if (context.matchedResult.hasUnresolvedSubstitutions(match.node)) {
1046
+ return [content];
1047
+ }
1048
+
1049
+ const colorText = context.matchedResult.getComputedText(match.node);
1050
+ const fakeSpan = document.body.appendChild(document.createElement('span'));
1051
+ fakeSpan.style.color = colorText;
1052
+ const resolvedColorText = window.getComputedStyle(fakeSpan).color;
1053
+ fakeSpan.remove();
1054
+
1055
+ const color = Common.Color.parse(resolvedColorText);
1056
+ if (!color) {
1057
+ return [content];
1058
+ }
1059
+
1060
+ const colorSwatch = new ColorRenderer(this.#stylesContainer, this.#treeElement).renderColorSwatch(color, content);
1061
+ context.addControl('color', colorSwatch);
1062
+
1063
+ return [colorSwatch, content];
1064
+ }
1065
+ }
1066
+
1027
1067
  // clang-format off
1028
1068
  export class AngleRenderer extends rendererBase(SDK.CSSPropertyParserMatchers.AngleMatch) {
1029
1069
  // clang-format on
@@ -1490,7 +1530,8 @@ export class ShadowRenderer extends rendererBase(SDK.CSSPropertyParserMatchers.S
1490
1530
  properties.push({value, source, propertyType: ShadowPropertyType.INSET, expansionContext});
1491
1531
  } else if (
1492
1532
  match instanceof SDK.CSSPropertyParserMatchers.ColorMatch ||
1493
- match instanceof SDK.CSSPropertyParserMatchers.ColorMixMatch) {
1533
+ match instanceof SDK.CSSPropertyParserMatchers.ColorMixMatch ||
1534
+ match instanceof SDK.CSSPropertyParserMatchers.ContrastColorMatch) {
1494
1535
  if (properties.find(({propertyType}) => propertyType === ShadowPropertyType.COLOR)) {
1495
1536
  return null;
1496
1537
  }
@@ -1950,6 +1991,7 @@ export function getPropertyRenderers(
1950
1991
  new VariableRenderer(stylesContainer, treeElement, matchedStyles, computedStyles, computedStyleExtraFields),
1951
1992
  new ColorRenderer(stylesContainer, treeElement),
1952
1993
  new ColorMixRenderer(stylesContainer, matchedStyles, computedStyles, computedStyleExtraFields, treeElement),
1994
+ new ContrastColorRenderer(stylesContainer, treeElement),
1953
1995
  new URLRenderer(style.parentRule, stylesContainer.node()),
1954
1996
  new AngleRenderer(treeElement),
1955
1997
  new LinkableNameRenderer(matchedStyles, stylesContainer),
@@ -2024,9 +2066,12 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
2024
2066
  this.listItemElement.textContent = '';
2025
2067
  }
2026
2068
 
2027
- this.property.addEventListener(SDK.CSSProperty.Events.LOCAL_VALUE_UPDATED, () => {
2028
- this.updateTitle();
2029
- });
2069
+ this.property.addEventListener(SDK.CSSProperty.Events.LOCAL_VALUE_UPDATED, this.updateTitle, this);
2070
+ }
2071
+
2072
+ override onunbind(): void {
2073
+ this.property.removeEventListener(SDK.CSSProperty.Events.LOCAL_VALUE_UPDATED, this.updateTitle, this);
2074
+ super.onunbind();
2030
2075
  }
2031
2076
 
2032
2077
  async gridNames(): Promise<Set<string>> {
@@ -94,6 +94,40 @@
94
94
  --override-styles-section-text-hover-text-decoration: underline;
95
95
  --override-styles-section-text-hover-cursor: default;
96
96
  }
97
+
98
+ & .section-collapse-icon {
99
+ width: 12px;
100
+ height: 12px;
101
+ margin-right: 2px;
102
+ margin-left: -2px;
103
+ vertical-align: middle;
104
+ cursor: pointer;
105
+ display: none;
106
+ }
107
+
108
+ &.collapsible .section-collapse-icon {
109
+ display: inline-block;
110
+ }
111
+
112
+ &.collapsed {
113
+ opacity: 60%;
114
+
115
+ & .style-properties {
116
+ display: none;
117
+ }
118
+
119
+ & .styles-section-subtitle {
120
+ display: none;
121
+ }
122
+
123
+ & .sidebar-pane-closing-brace {
124
+ display: none;
125
+ }
126
+
127
+ & .sidebar-pane-open-brace::after {
128
+ content: "}";
129
+ }
130
+ }
97
131
  }
98
132
 
99
133
  .sidebar-pane-closing-brace {
@@ -42,6 +42,7 @@ const UIStrings = {
42
42
  } as const;
43
43
  const str_ = i18n.i18n.registerUIStrings('panels/issues/AffectedSelectivePermissionsInterventionView.ts', UIStrings);
44
44
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
45
+ const {widget} = UI.Widget;
45
46
 
46
47
  export class AffectedSelectivePermissionsInterventionView extends AffectedResourcesView {
47
48
  readonly #linkifier = new Components.Linkifier.Linkifier();
@@ -103,13 +104,10 @@ export class AffectedSelectivePermissionsInterventionView extends AffectedResour
103
104
  const debuggerWorkspaceBinding = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
104
105
  const stackTraceTranslated =
105
106
  await debuggerWorkspaceBinding.createStackTraceFromProtocolRuntime(stackTrace, issuesModel.target());
106
- return html`
107
- <devtools-widget .widgetConfig=${UI.Widget.widgetConfig(Components.JSPresentationUtils.StackTracePreviewContent, {
107
+ return html`${widget(Components.JSPresentationUtils.StackTracePreviewContent, {
108
108
  stackTrace: stackTraceTranslated,
109
109
  options: {expandable: true},
110
- })}>
111
- </devtools-widget>
112
- `;
110
+ })}`;
113
111
  }
114
112
 
115
113
  update(): void {
@@ -20,6 +20,7 @@ import {
20
20
  } from './LayerViewHost.js';
21
21
 
22
22
  const {html, nothing} = Lit;
23
+ const {widget} = UI.Widget;
23
24
 
24
25
  const UIStrings = {
25
26
  /**
@@ -157,7 +158,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
157
158
  if (!layer) {
158
159
  // clang-format off
159
160
  Lit.render(html`<div class="layer-details-container">
160
- <devtools-widget class="learn-more" .widgetConfig=${UI.Widget.widgetConfig(UI.EmptyWidget.EmptyWidget, {
161
+ <devtools-widget class="learn-more" ${widget(UI.EmptyWidget.EmptyWidget, {
161
162
  header: i18nString(UIStrings.noLayerSelected),
162
163
  text: i18nString(UIStrings.selectALayerToSeeItsDetails)})}>
163
164
  </devtools-widget>
@@ -27,6 +27,7 @@ import {
27
27
  import {Events as TransformControllerEvents, TransformController} from './TransformController.js';
28
28
 
29
29
  const {html, render, Directives: {ref}} = Lit;
30
+ const {widget} = UI.Widget;
30
31
 
31
32
  const UIStrings = {
32
33
  /**
@@ -108,11 +109,11 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
108
109
  ${layers3DViewStyles}
109
110
  </style>
110
111
  ${input.panelToolbar}
111
- ${input.error === 'missing-root' ? html`<div><devtools-widget .widgetConfig=${UI.Widget.widgetConfig(UI.EmptyWidget.EmptyWidget, {
112
+ ${input.error === 'missing-root' ? html`<div>${widget(UI.EmptyWidget.EmptyWidget, {
112
113
  header: i18nString(UIStrings.noLayerInformation),
113
114
  text: i18nString(UIStrings.layerExplanation)
114
- })}></devtools-widget></div>` : Lit.nothing}
115
- ${input.error === 'webgl-disabled' ? html`<div><devtools-widget .widgetConfig=${UI.Widget.widgetConfig(UI.EmptyWidget.EmptyWidget, {
115
+ })}</div>` : Lit.nothing}
116
+ ${input.error === 'webgl-disabled' ? html`<div>${widget(UI.EmptyWidget.EmptyWidget, {
116
117
  header: i18nString(UIStrings.cantDisplayLayers),
117
118
  text: i18nString(UIStrings.webglSupportIsDisabledInYour),
118
119
  extraElements: [
@@ -123,7 +124,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
123
124
  }
124
125
  )
125
126
  ],
126
- })}></devtools-widget></div>` : Lit.nothing}
127
+ })}</div>` : Lit.nothing}
127
128
  <canvas
128
129
  tabindex="0"
129
130
  jslog=${VisualLogging.canvas('layers').track({