chrome-devtools-frontend 1.0.1602348 → 1.0.1603822

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 (105) hide show
  1. package/.agents/skills/version-control/SKILL.md +17 -2
  2. package/AUTHORS +1 -0
  3. package/front_end/core/common/Settings.ts +1 -871
  4. package/front_end/core/common/VersionController.ts +880 -0
  5. package/front_end/core/common/common.ts +2 -0
  6. package/front_end/core/platform/HostRuntime.ts +9 -3
  7. package/front_end/core/protocol_client/InspectorBackend.ts +8 -0
  8. package/front_end/core/root/Runtime.ts +5 -0
  9. package/front_end/core/sdk/OverlayModel.ts +13 -13
  10. package/front_end/core/sdk/OverlayPersistentHighlighter.ts +13 -10
  11. package/front_end/core/sdk/RuntimeModel.ts +5 -5
  12. package/front_end/core/sdk/ServiceWorkerManager.ts +4 -2
  13. package/front_end/core/sdk/Target.ts +5 -0
  14. package/front_end/core/sdk/TargetManager.ts +5 -0
  15. package/front_end/core/sdk/WebMCPModel.ts +104 -0
  16. package/front_end/core/sdk/sdk.ts +2 -0
  17. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +13 -19
  18. package/front_end/generated/InspectorBackendCommands.ts +3 -0
  19. package/front_end/generated/protocol-mapping.d.ts +8 -0
  20. package/front_end/generated/protocol-proxy-api.d.ts +10 -0
  21. package/front_end/generated/protocol.ts +57 -0
  22. package/front_end/models/ai_assistance/AiConversation.ts +3 -3
  23. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +50 -0
  24. package/front_end/models/ai_assistance/agents/AiAgent.ts +14 -1
  25. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +19 -4
  26. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +7 -1
  27. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +30 -7
  28. package/front_end/models/ai_assistance/agents/StylingAgent.ts +0 -23
  29. package/front_end/models/ai_assistance/data_formatters/LighthouseFormatter.snapshot.txt +60 -9
  30. package/front_end/models/ai_assistance/data_formatters/LighthouseFormatter.ts +71 -15
  31. package/front_end/models/heap_snapshot_model/HeapSnapshotModel.ts +7 -7
  32. package/front_end/models/javascript_metadata/NativeFunctions.js +6 -2
  33. package/front_end/models/lighthouse/LighthouseReporterTypes.ts +10 -8
  34. package/front_end/models/lighthouse/RunTypes.ts +3 -1
  35. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +13 -5
  36. package/front_end/panels/ai_assistance/components/ChatMessage.ts +143 -18
  37. package/front_end/panels/ai_assistance/components/WalkthroughView.ts +30 -10
  38. package/front_end/panels/ai_assistance/components/chatMessage.css +58 -3
  39. package/front_end/panels/ai_assistance/components/walkthroughView.css +35 -5
  40. package/front_end/panels/application/AppManifestView.ts +2 -2
  41. package/front_end/panels/application/BackgroundServiceView.ts +9 -9
  42. package/front_end/panels/application/FrameDetailsView.ts +4 -13
  43. package/front_end/panels/application/IndexedDBViews.ts +1 -1
  44. package/front_end/panels/application/ServiceWorkerCacheViews.ts +3 -3
  45. package/front_end/panels/application/components/PermissionsPolicySection.ts +1 -1
  46. package/front_end/panels/application/components/permissionsPolicySection.css +54 -52
  47. package/front_end/panels/application/frameDetailsReportView.css +13 -1
  48. package/front_end/panels/common/ThrottlingUtils.ts +46 -0
  49. package/front_end/panels/common/common.ts +1 -0
  50. package/front_end/panels/elements/CSSValueTraceView.ts +9 -1
  51. package/front_end/panels/elements/ComputedStyleWidget.ts +11 -1
  52. package/front_end/panels/elements/PropertiesWidget.ts +14 -13
  53. package/front_end/panels/elements/PropertyRenderer.ts +10 -9
  54. package/front_end/panels/elements/StandaloneStylesContainer.ts +15 -5
  55. package/front_end/panels/elements/StylePropertiesSection.ts +0 -49
  56. package/front_end/panels/elements/StylePropertyTreeElement.ts +20 -0
  57. package/front_end/panels/elements/StylesContainer.ts +0 -1
  58. package/front_end/panels/elements/StylesSidebarPane.ts +65 -31
  59. package/front_end/panels/elements/stylePropertiesTreeOutline.css +5 -0
  60. package/front_end/panels/issues/AffectedSelectivePermissionsInterventionView.ts +2 -2
  61. package/front_end/panels/lighthouse/LighthouseController.ts +4 -1
  62. package/front_end/panels/media/EventDisplayTable.ts +3 -2
  63. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +14 -0
  64. package/front_end/panels/network/EventSourceMessagesView.ts +2 -2
  65. package/front_end/panels/network/ResourceChunkView.ts +1 -1
  66. package/front_end/panels/profiler/HeapDetachedElementsView.ts +9 -4
  67. package/front_end/panels/profiler/HeapProfileView.ts +8 -4
  68. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +40 -33
  69. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +1 -1
  70. package/front_end/panels/profiler/HeapSnapshotProxy.ts +1 -1
  71. package/front_end/panels/profiler/HeapSnapshotView.ts +12 -18
  72. package/front_end/panels/profiler/LiveHeapProfileView.ts +3 -4
  73. package/front_end/panels/profiler/ProfileHeader.ts +5 -11
  74. package/front_end/panels/profiler/ProfileView.ts +1 -10
  75. package/front_end/panels/sensors/SensorsView.ts +24 -43
  76. package/front_end/panels/settings/keybindsSettingsTab.css +25 -31
  77. package/front_end/panels/timeline/EventsTimelineTreeView.ts +2 -2
  78. package/front_end/panels/timeline/ThirdPartyTreeView.ts +8 -0
  79. package/front_end/panels/timeline/TimelinePanel.ts +14 -2
  80. package/front_end/panels/timeline/TimelineTreeView.ts +19 -17
  81. package/front_end/panels/timeline/components/FieldSettingsDialog.ts +5 -9
  82. package/front_end/panels/timeline/components/LiveMetricsView.ts +1 -2
  83. package/front_end/panels/timeline/components/OriginMap.ts +176 -159
  84. package/front_end/panels/timeline/components/originMap.css +4 -51
  85. package/front_end/panels/timeline/components/timelineRangeSummaryView.css +3 -1
  86. package/front_end/panels/timeline/thirdPartyTreeView.css +6 -0
  87. package/front_end/panels/timeline/timeline-meta.ts +11 -0
  88. package/front_end/panels/timeline/utils/Helpers.ts +5 -25
  89. package/front_end/panels/webauthn/WebauthnPane.ts +52 -0
  90. package/front_end/third_party/acorn/README.chromium +1 -0
  91. package/front_end/third_party/chromium/README.chromium +1 -1
  92. package/front_end/ui/components/{list → lists}/List.ts +1 -1
  93. package/front_end/ui/components/{list → lists}/list.css +0 -1
  94. package/front_end/ui/legacy/Treeoutline.ts +7 -3
  95. package/front_end/ui/legacy/UIUtils.ts +13 -11
  96. package/front_end/ui/legacy/Widget.ts +5 -0
  97. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +1 -1
  98. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
  99. package/front_end/ui/legacy/components/data_grid/SortableDataGrid.ts +2 -2
  100. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +39 -23
  101. package/front_end/ui/legacy/components/perf_ui/GCActionDelegate.ts +20 -4
  102. package/front_end/ui/legacy/treeoutline.css +4 -0
  103. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  104. package/package.json +1 -1
  105. /package/front_end/ui/components/{list → lists}/lists.ts +0 -0
@@ -384,15 +384,15 @@ export class BackgroundServiceView extends UI.Widget.VBox {
384
384
  }
385
385
 
386
386
  private createDataGrid(): DataGrid.DataGrid.DataGridImpl<EventData> {
387
- const columns = ([
388
- {id: 'id', title: '#', weight: 1},
389
- {id: 'timestamp', title: i18nString(UIStrings.timestamp), weight: 7},
390
- {id: 'event-name', title: i18nString(UIStrings.event), weight: 8},
391
- {id: 'origin', title: i18nString(UIStrings.origin), weight: 8},
392
- {id: 'storage-key', title: i18nString(UIStrings.storageKey), weight: 8},
393
- {id: 'sw-scope', title: i18nString(UIStrings.swScope), weight: 4},
394
- {id: 'instance-id', title: i18nString(UIStrings.instanceId), weight: 8},
395
- ] as DataGrid.DataGrid.ColumnDescriptor[]);
387
+ const columns: DataGrid.DataGrid.ColumnDescriptor[] = [
388
+ {id: 'id', title: '#' as Common.UIString.LocalizedString, weight: 1, sortable: false},
389
+ {id: 'timestamp', title: i18nString(UIStrings.timestamp), weight: 7, sortable: false},
390
+ {id: 'event-name', title: i18nString(UIStrings.event), weight: 8, sortable: false},
391
+ {id: 'origin', title: i18nString(UIStrings.origin), weight: 8, sortable: false},
392
+ {id: 'storage-key', title: i18nString(UIStrings.storageKey), weight: 8, sortable: false},
393
+ {id: 'sw-scope', title: i18nString(UIStrings.swScope), weight: 4, sortable: false},
394
+ {id: 'instance-id', title: i18nString(UIStrings.instanceId), weight: 8, sortable: false},
395
+ ];
396
396
  const dataGrid = new DataGrid.DataGrid.DataGridImpl({
397
397
  displayName: i18nString(UIStrings.backgroundServices),
398
398
  columns,
@@ -268,7 +268,7 @@ export interface FrameDetailsReportViewData {
268
268
  adScriptAncestry: Protocol.Network.AdAncestry|null;
269
269
  }
270
270
 
271
- interface FrameDetailsViewInput {
271
+ export interface FrameDetailsViewInput {
272
272
  frame: SDK.ResourceTreeModel.ResourceTreeFrame;
273
273
  target: SDK.Target.Target|null;
274
274
  creationStackTrace: StackTrace.StackTrace.StackTrace|null;
@@ -282,9 +282,9 @@ interface FrameDetailsViewInput {
282
282
  onRevealInSources: () => void;
283
283
  }
284
284
 
285
- type View = (input: FrameDetailsViewInput, output: undefined, target: HTMLElement) => void;
285
+ export type View = (input: FrameDetailsViewInput, output: undefined, target: HTMLElement) => void;
286
286
 
287
- const DEFAULT_VIEW: View = (input, _output, target) => {
287
+ export const DEFAULT_VIEW: View = (input, _output, target) => {
288
288
  if (!input.frame) {
289
289
  return;
290
290
  }
@@ -892,16 +892,7 @@ export class FrameDetailsReportView extends UI.Widget.Widget {
892
892
  const result = await this.#frame?.parentFrame()?.getAdScriptAncestry(this.#frame?.id);
893
893
  if (result && result.ancestryChain.length > 0) {
894
894
  this.#adScriptAncestry = result;
895
-
896
- // Obtain the Target associated with the first ad script, because in most scenarios all
897
- // scripts share the same debuggerId. However, discrepancies might arise when content scripts
898
- // from browser extensions are involved. We will monitor the debugging experiences and revisit
899
- // this approach if it proves problematic.
900
- const firstScript = this.#adScriptAncestry.ancestryChain[0];
901
- const debuggerModel = firstScript?.debuggerId ?
902
- await SDK.DebuggerModel.DebuggerModel.modelForDebuggerId(firstScript.debuggerId) :
903
- null;
904
- this.#target = debuggerModel?.target() ?? null;
895
+ this.#target = this.#frame?.resourceTreeModel().target() ?? null;
905
896
  }
906
897
 
907
898
  const frame = this.#frame;
@@ -320,7 +320,7 @@ export class IDBDataView extends UI.View.SimpleView {
320
320
  private createDataGrid(): DataGrid.DataGrid.DataGridImpl<unknown> {
321
321
  const keyPath = this.isIndex && this.index ? this.index.keyPath : this.objectStore.keyPath;
322
322
 
323
- const columns = ([] as DataGrid.DataGrid.ColumnDescriptor[]);
323
+ const columns: DataGrid.DataGrid.ColumnDescriptor[] = [];
324
324
 
325
325
  // Create column defaults so that we avoid repetition below.
326
326
  const columnDefaults: Partial<DataGrid.DataGrid.ColumnDescriptor> = {
@@ -210,8 +210,8 @@ export class ServiceWorkerCacheView extends UI.View.SimpleView {
210
210
  }
211
211
 
212
212
  private createDataGrid(): DataGrid.DataGrid.DataGridImpl<DataGridNode> {
213
- const columns = ([
214
- {id: 'number', title: '#', sortable: false, width: '3px'},
213
+ const columns: DataGrid.DataGrid.ColumnDescriptor[] = [
214
+ {id: 'number', title: '#' as Common.UIString.LocalizedString, sortable: false, width: '3px'},
215
215
  {id: 'name', title: i18nString(UIStrings.name), weight: 4, sortable: true},
216
216
  {
217
217
  id: 'response-type',
@@ -237,7 +237,7 @@ export class ServiceWorkerCacheView extends UI.View.SimpleView {
237
237
  sortable: true,
238
238
  },
239
239
  {id: 'vary-header', title: i18n.i18n.lockedString('Vary Header'), weight: 1, sortable: true},
240
- ] as DataGrid.DataGrid.ColumnDescriptor[]);
240
+ ];
241
241
  const dataGrid = new DataGrid.DataGrid.DataGridImpl({
242
242
  displayName: i18nString(UIStrings.serviceWorkerCache),
243
243
  columns,
@@ -219,7 +219,7 @@ export class PermissionsPolicySection extends UI.Widget.Widget {
219
219
  #view: View;
220
220
 
221
221
  constructor(element?: HTMLElement, view = DEFAULT_VIEW) {
222
- super(element, {useShadowDom: true});
222
+ super(element, {useShadowDom: false});
223
223
  this.#view = view;
224
224
  }
225
225
 
@@ -4,56 +4,58 @@
4
4
  * found in the LICENSE file.
5
5
  */
6
6
 
7
- :host {
8
- display: contents;
9
- }
10
-
11
- .text-ellipsis {
12
- overflow: hidden;
13
- text-overflow: ellipsis;
14
- white-space: nowrap;
15
- }
16
-
17
- .link,
18
- .devtools-link {
19
- color: var(--sys-color-primary);
20
- text-decoration: underline;
21
- cursor: pointer;
22
- outline-offset: 2px;
23
- }
24
-
25
- button.link {
26
- border: none;
27
- background: none;
28
- font-family: inherit;
29
- font-size: inherit;
30
- }
31
-
32
- .policies-list {
33
- padding-top: 3px;
34
- }
35
-
36
- .permissions-row {
37
- display: flex;
38
- line-height: 22px;
39
- }
40
-
41
- .permissions-row div {
42
- padding-right: 5px;
43
- }
44
-
45
- .feature-name {
46
- width: 135px;
47
- }
48
-
49
- .allowed-icon {
50
- vertical-align: sub;
51
- }
52
-
53
- .block-reason {
54
- width: 215px;
55
- }
56
-
57
- .disabled-features-button {
58
- padding-left: var(--sys-size-3);
7
+ @scope to (devtools-widget > *) {
8
+ :scope {
9
+ display: contents;
10
+ }
11
+
12
+ .text-ellipsis {
13
+ overflow: hidden;
14
+ text-overflow: ellipsis;
15
+ white-space: nowrap;
16
+ }
17
+
18
+ .link,
19
+ .devtools-link {
20
+ color: var(--sys-color-primary);
21
+ text-decoration: underline;
22
+ cursor: pointer;
23
+ outline-offset: 2px;
24
+ }
25
+
26
+ button.link {
27
+ border: none;
28
+ background: none;
29
+ font-family: inherit;
30
+ font-size: inherit;
31
+ }
32
+
33
+ .policies-list {
34
+ padding-top: 3px;
35
+ }
36
+
37
+ .permissions-row {
38
+ display: flex;
39
+ line-height: 22px;
40
+ }
41
+
42
+ .permissions-row div {
43
+ padding-right: 5px;
44
+ }
45
+
46
+ .feature-name {
47
+ width: 135px;
48
+ }
49
+
50
+ .allowed-icon {
51
+ vertical-align: sub;
52
+ }
53
+
54
+ .block-reason {
55
+ width: 215px;
56
+ }
57
+
58
+ .disabled-features-button {
59
+ padding-left: var(--sys-size-3);
60
+ }
59
61
  }
@@ -79,6 +79,18 @@ button.text-link {
79
79
  display: flex;
80
80
  }
81
81
 
82
+ .inline-items devtools-button {
83
+ flex: 0 0 20px;
84
+ width: 20px;
85
+ height: 20px;
86
+ }
87
+
88
+ .inline-items .text-ellipsis {
89
+ flex: 0 1 auto;
90
+ min-width: 0;
91
+ padding-left: 2px;
92
+ }
93
+
82
94
  .span-cols {
83
95
  grid-column-start: span 2;
84
96
  margin-left: var(--sys-size-9);
@@ -115,4 +127,4 @@ button.text-link {
115
127
  color: linktext;
116
128
  text-decoration-color: linktext;
117
129
  }
118
- }
130
+ }
@@ -0,0 +1,46 @@
1
+ // Copyright 2026 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as SDK from '../../core/sdk/sdk.js';
6
+ import * as CrUXManager from '../../models/crux-manager/crux-manager.js';
7
+
8
+ export interface ThrottlingRecommendations {
9
+ cpuOption: SDK.CPUThrottlingManager.CPUThrottlingOption|null;
10
+ networkConditions: SDK.NetworkManager.Conditions|null;
11
+ }
12
+
13
+ /**
14
+ * Computes the recommended CPU and network throttling presets based on CrUX
15
+ * field metric data.
16
+ */
17
+ export function getThrottlingRecommendations(): ThrottlingRecommendations {
18
+ const cruxManager = CrUXManager.CrUXManager.instance();
19
+ const roundTripTimeMetricData = cruxManager.getSelectedFieldMetricData('round_trip_time');
20
+
21
+ let cpuOption: SDK.CPUThrottlingManager.CPUThrottlingOption =
22
+ SDK.CPUThrottlingManager.CalibratedMidTierMobileThrottlingOption;
23
+ if (cpuOption.rate() === 0) {
24
+ cpuOption = SDK.CPUThrottlingManager.MidTierThrottlingOption;
25
+ }
26
+
27
+ const networkConditions = getRecommendedNetworkConditions(roundTripTimeMetricData);
28
+
29
+ return {
30
+ cpuOption,
31
+ networkConditions,
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Computes the recommended network throttling preset based on CrUX RTT field
37
+ * metric data. Returns null if no RTT data is available or no preset matches.
38
+ */
39
+ export function getRecommendedNetworkConditions(roundTripTimeMetricData?: CrUXManager.MetricResponse):
40
+ SDK.NetworkManager.Conditions|null {
41
+ if (roundTripTimeMetricData?.percentiles) {
42
+ const rtt = Number(roundTripTimeMetricData.percentiles.p75);
43
+ return SDK.NetworkManager.getRecommendedNetworkPreset(rtt);
44
+ }
45
+ return null;
46
+ }
@@ -109,5 +109,6 @@ export * as ExtensionServer from './ExtensionServer.js';
109
109
  export * as ExtensionView from './ExtensionView.js';
110
110
  export * as PersistenceUtils from './PersistenceUtils.js';
111
111
  export * as DOMLinkifier from './DOMLinkifier.js';
112
+ export * as ThrottlingUtils from './ThrottlingUtils.js';
112
113
  export * as ExtensionIframe from './ExtensionView.js';
113
114
  export {CopyChangesToPrompt} from './CopyChangesToPrompt.js';
@@ -128,6 +128,7 @@ export class CSSValueTraceView extends UI.Widget.VBox {
128
128
  expandPercentagesInShorthands: boolean,
129
129
  shorthandPositionOffset: number,
130
130
  focus: boolean,
131
+ signal?: AbortSignal,
131
132
  ): Promise<void> {
132
133
  const matchedResult = subexpression === null ?
133
134
  property.parseValue(matchedStyles, computedStyles) :
@@ -136,7 +137,7 @@ export class CSSValueTraceView extends UI.Widget.VBox {
136
137
  return undefined;
137
138
  }
138
139
  return await this.#showTrace(
139
- property, matchedResult, renderers, expandPercentagesInShorthands, shorthandPositionOffset, focus);
140
+ property, matchedResult, renderers, expandPercentagesInShorthands, shorthandPositionOffset, focus, signal);
140
141
  }
141
142
 
142
143
  async #showTrace(
@@ -146,6 +147,7 @@ export class CSSValueTraceView extends UI.Widget.VBox {
146
147
  expandPercentagesInShorthands: boolean,
147
148
  shorthandPositionOffset: number,
148
149
  focus: boolean,
150
+ signal?: AbortSignal,
149
151
  ): Promise<void> {
150
152
  this.#highlighting = new Highlighting();
151
153
  const rendererMap = new Map(renderers.map(r => [r.matchType, r]));
@@ -165,6 +167,7 @@ export class CSSValueTraceView extends UI.Widget.VBox {
165
167
  /* cssControls */ undefined,
166
168
  /* options */ {},
167
169
  tracing,
170
+ signal,
168
171
  );
169
172
  substitutions.push(Renderer.render(matchedResult.ast.tree, context).nodes);
170
173
  }
@@ -180,6 +183,7 @@ export class CSSValueTraceView extends UI.Widget.VBox {
180
183
  /* cssControls */ undefined,
181
184
  /* options */ {},
182
185
  tracing,
186
+ signal,
183
187
  );
184
188
  evaluations.push(Renderer.render(matchedResult.ast.tree, context).nodes);
185
189
  asyncCallbackResults.push(tracing.runAsyncEvaluations());
@@ -199,6 +203,10 @@ export class CSSValueTraceView extends UI.Widget.VBox {
199
203
  property,
200
204
  rendererMap,
201
205
  matchedResult,
206
+ undefined,
207
+ {},
208
+ undefined,
209
+ signal,
202
210
  );
203
211
  this.#evaluations.push(Renderer.render(matchedResult.ast.tree, context).nodes);
204
212
  }
@@ -331,6 +331,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
331
331
 
332
332
  #computedStylesTree = new TreeOutline.TreeOutline.TreeOutline<ComputedStyleData>();
333
333
  #treeData?: TreeOutline.TreeOutline.TreeOutlineData<ComputedStyleData>;
334
+ #enableNarrowViewResizing = true;
334
335
  readonly #view: View;
335
336
 
336
337
  /**
@@ -378,10 +379,19 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
378
379
  }
379
380
 
380
381
  override onResize(): void {
381
- const isNarrow = this.contentElement.offsetWidth < 260;
382
+ const isNarrow = this.#enableNarrowViewResizing && this.contentElement.offsetWidth < 260;
382
383
  this.#computedStylesTree.classList.toggle('computed-narrow', isNarrow);
383
384
  }
384
385
 
386
+ get enableNarrowViewResizing(): boolean {
387
+ return this.#enableNarrowViewResizing;
388
+ }
389
+
390
+ set enableNarrowViewResizing(enable: boolean) {
391
+ this.#enableNarrowViewResizing = enable;
392
+ this.onResize();
393
+ }
394
+
385
395
  get filterText(): RegExp|string {
386
396
  if (this.#filterIsRegex) {
387
397
  return new RegExp(this.#filterText);
@@ -40,7 +40,7 @@ import * as Platform from '../../core/platform/platform.js';
40
40
  import * as SDK from '../../core/sdk/sdk.js';
41
41
  import * as ObjectUI from '../../ui/legacy/components/object_ui/object_ui.js';
42
42
  import * as UI from '../../ui/legacy/legacy.js';
43
- import {html, nothing, render} from '../../ui/lit/lit.js';
43
+ import {Directives, html, nothing, render} from '../../ui/lit/lit.js';
44
44
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
45
45
 
46
46
  import propertiesWidgetStyles from './propertiesWidget.css.js';
@@ -48,6 +48,7 @@ import propertiesWidgetStyles from './propertiesWidget.css.js';
48
48
  const OBJECT_GROUP_NAME = 'properties-sidebar-pane';
49
49
 
50
50
  const {bindToSetting} = UI.UIUtils;
51
+ const {repeat} = Directives;
51
52
 
52
53
  const UIStrings = {
53
54
  /**
@@ -75,7 +76,6 @@ interface PropertiesWidgetInput {
75
76
  onFilterChanged: (e: CustomEvent<string>) => void;
76
77
  onRegexToggled: () => void;
77
78
  isRegex: boolean;
78
- treeOutline: ObjectUI.ObjectPropertiesSection.ObjectPropertiesSectionsTreeOutline;
79
79
  objectTree: ObjectUI.ObjectPropertiesSection.ObjectTree|null;
80
80
  allChildrenFiltered: boolean;
81
81
  }
@@ -103,7 +103,17 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
103
103
  ${input.objectTree && input.allChildrenFiltered ? html`
104
104
  <div class="gray-info-message">${i18nString(UIStrings.noMatchingProperty)}</div>
105
105
  ` : nothing}
106
- ${input.treeOutline.element}
106
+ <devtools-tree .template=${html`
107
+ <ul role=tree class="source-code object-properties-section">
108
+ <style>${ObjectUI.ObjectPropertiesSection.objectValueStyles}</style>;
109
+ <style>${ObjectUI.ObjectPropertiesSection.objectPropertiesSectionStyles}</style>;
110
+ ${repeat(ObjectUI.ObjectPropertiesSection.ObjectPropertyTreeElement.createPropertyNodes(
111
+ input.objectTree?.children ?? {},
112
+ true /* skipProto */,
113
+ true /* skipGettersAndSetters */),
114
+ node => html`<devtools-tree-wrapper .treeElement=${node}></devtools-tree-wrapper>`)}
115
+ </ul>
116
+ `}></devtools-tree>
107
117
  </div>`, target);
108
118
  // clang-format on
109
119
  };
@@ -218,15 +228,7 @@ export class PropertiesWidget extends UI.Widget.VBox {
218
228
 
219
229
  override async performUpdate(): Promise<void> {
220
230
  await this.#updateNodeIfRequired();
221
- if (!this.#objectTree) {
222
- this.treeOutline.removeChildren();
223
- } else {
224
- const treeElement = this.treeOutline.rootElement();
225
- treeElement.removeChildren();
226
- ObjectUI.ObjectPropertiesSection.ObjectPropertyTreeElement.populateWithProperties(
227
- treeElement, await this.#objectTree.populateChildrenIfNeeded(), true /* skipProto */,
228
- true /* skipGettersAndSetters */);
229
- }
231
+ await this.#objectTree?.populateChildrenIfNeeded();
230
232
  const allChildrenFiltered =
231
233
  !(this.#objectTree?.children?.accessors?.some(c => !c.isFiltered) ||
232
234
  this.#objectTree?.children?.arrayRanges?.some(() => true) ||
@@ -237,7 +239,6 @@ export class PropertiesWidget extends UI.Widget.VBox {
237
239
  onFilterChanged: this.onFilterChanged.bind(this),
238
240
  onRegexToggled: this.onRegexToggled.bind(this),
239
241
  isRegex: this.#isRegex,
240
- treeOutline: this.treeOutline,
241
242
  allChildrenFiltered,
242
243
  objectTree: this.#objectTree,
243
244
  },
@@ -354,7 +354,7 @@ export class RenderingContext {
354
354
  MatchRenderer<SDK.CSSPropertyParser.Match>>,
355
355
  readonly matchedResult: SDK.CSSPropertyParser.BottomUpTreeMatching,
356
356
  readonly cssControls?: SDK.CSSPropertyParser.CSSControlMap, readonly options: {readonly?: boolean} = {},
357
- readonly tracing?: TracingContext) {
357
+ readonly tracing?: TracingContext, readonly signal?: AbortSignal) {
358
358
  }
359
359
 
360
360
  addControl(cssType: string, control: HTMLElement): void {
@@ -414,11 +414,12 @@ export class Renderer extends SDK.CSSPropertyParser.TreeWalker {
414
414
  readonly?: boolean,
415
415
  },
416
416
  tracing: TracingContext|undefined,
417
+ signal: AbortSignal|undefined,
417
418
  ) {
418
419
  super(ast);
419
420
  this.#matchedResult = matchedResult;
420
421
  this.#context =
421
- new RenderingContext(this.ast, property, renderers, this.#matchedResult, cssControls, options, tracing);
422
+ new RenderingContext(this.ast, property, renderers, this.#matchedResult, cssControls, options, tracing, signal);
422
423
  }
423
424
 
424
425
  static render(nodeOrNodes: CodeMirror.SyntaxNode|CodeMirror.SyntaxNode[], context: RenderingContext):
@@ -430,7 +431,7 @@ export class Renderer extends SDK.CSSPropertyParser.TreeWalker {
430
431
  const renderers = nodeOrNodes.map(
431
432
  node => this.walkExcludingSuccessors(
432
433
  context.ast.subtree(node), context.property, context.renderers, context.matchedResult, cssControls,
433
- context.options, context.tracing));
434
+ context.options, context.tracing, context.signal));
434
435
  const nodes = renderers.map(node => node.#output).reduce(mergeWithSpacing, []);
435
436
  return {nodes, cssControls};
436
437
  }
@@ -491,8 +492,8 @@ export class Renderer extends SDK.CSSPropertyParser.TreeWalker {
491
492
  static renderValueElement(
492
493
  property: SDK.CSSProperty.CSSProperty|{name: string, value: string},
493
494
  matchedResult: SDK.CSSPropertyParser.BottomUpTreeMatching|null,
494
- renderers: Array<MatchRenderer<SDK.CSSPropertyParser.Match>>,
495
- tracing?: TracingContext): {valueElement: HTMLElement, cssControls: SDK.CSSPropertyParser.CSSControlMap} {
495
+ renderers: Array<MatchRenderer<SDK.CSSPropertyParser.Match>>, tracing?: TracingContext,
496
+ signal?: AbortSignal): {valueElement: HTMLElement, cssControls: SDK.CSSPropertyParser.CSSControlMap} {
496
497
  const valueElement = document.createElement('span');
497
498
  valueElement.setAttribute(
498
499
  'jslog', `${VisualLogging.value().track({
@@ -502,7 +503,7 @@ export class Renderer extends SDK.CSSPropertyParser.TreeWalker {
502
503
  UI.ARIAUtils.setLabel(valueElement, i18nString(UIStrings.cssPropertyValue, {PH1: property.value}));
503
504
  valueElement.className = 'value';
504
505
  valueElement.tabIndex = -1;
505
- const {nodes, cssControls} = this.renderValueNodes(property, matchedResult, renderers, tracing);
506
+ const {nodes, cssControls} = this.renderValueNodes(property, matchedResult, renderers, tracing, signal);
506
507
  nodes.forEach(node => valueElement.appendChild(node));
507
508
  valueElement.normalize();
508
509
  return {valueElement, cssControls};
@@ -511,8 +512,8 @@ export class Renderer extends SDK.CSSPropertyParser.TreeWalker {
511
512
  static renderValueNodes(
512
513
  property: SDK.CSSProperty.CSSProperty|{name: string, value: string},
513
514
  matchedResult: SDK.CSSPropertyParser.BottomUpTreeMatching|null,
514
- renderers: Array<MatchRenderer<SDK.CSSPropertyParser.Match>>,
515
- tracing?: TracingContext): {nodes: Node[], cssControls: SDK.CSSPropertyParser.CSSControlMap} {
515
+ renderers: Array<MatchRenderer<SDK.CSSPropertyParser.Match>>, tracing?: TracingContext,
516
+ signal?: AbortSignal): {nodes: Node[], cssControls: SDK.CSSPropertyParser.CSSControlMap} {
516
517
  if (!matchedResult) {
517
518
  return {nodes: [document.createTextNode(property.value)], cssControls: new Map()};
518
519
  }
@@ -524,7 +525,7 @@ export class Renderer extends SDK.CSSPropertyParser.TreeWalker {
524
525
 
525
526
  const context = new RenderingContext(
526
527
  matchedResult.ast, property instanceof SDK.CSSProperty.CSSProperty ? property : null, rendererMap,
527
- matchedResult, undefined, {}, tracing);
528
+ matchedResult, undefined, {}, tracing, signal);
528
529
  return Renderer.render([matchedResult.ast.tree, ...matchedResult.ast.trailingNodes], context);
529
530
  }
530
531
  }
@@ -114,10 +114,7 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
114
114
  return this.#webCustomData;
115
115
  }
116
116
 
117
- async #updateSections(): Promise<void> {
118
- for (const section of this.#sections) {
119
- section.dispose();
120
- }
117
+ async #updateSections(signal?: AbortSignal): Promise<void> {
121
118
  const node = this.node();
122
119
  if (!node) {
123
120
  this.#sections = [];
@@ -126,6 +123,10 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
126
123
 
127
124
  const cssModel = node.domModel().cssModel();
128
125
  const matchedStyles = await cssModel.cachedMatchedCascadeForNode(node);
126
+ if (signal?.aborted) {
127
+ return;
128
+ }
129
+
129
130
  const parentNodeId = matchedStyles?.getParentLayoutNodeId();
130
131
 
131
132
  const [parentStyles, computedStyles, extraStyles] = await Promise.all([
@@ -133,6 +134,10 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
133
134
  cssModel.getComputedStyleExtraFields(node.id)
134
135
  ]);
135
136
 
137
+ if (signal?.aborted) {
138
+ return;
139
+ }
140
+
136
141
  if (!matchedStyles) {
137
142
  return;
138
143
  }
@@ -142,6 +147,7 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
142
147
  for (const style of matchedStyles.nodeStyles()) {
143
148
  const section = new StylePropertiesSection(
144
149
  this, matchedStyles, style, sectionIdx++, computedStyles, parentStyles, extraStyles);
150
+ section.update(true);
145
151
  newSections.push(section);
146
152
  this.sectionByElement.set(section.element, section);
147
153
  }
@@ -150,7 +156,10 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
150
156
  this.swatchPopoverHelper().reposition();
151
157
  }
152
158
 
153
- override async performUpdate(): Promise<void> {
159
+ override async performUpdate(signal?: AbortSignal): Promise<void> {
160
+ await this.#updateSections(signal);
161
+ signal?.throwIfAborted();
162
+
154
163
  const viewInput: ViewInput = {
155
164
  sections: this.#sections.filter(section => !section.isHidden()),
156
165
  };
@@ -178,6 +187,7 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
178
187
  return;
179
188
  }
180
189
  this.#computedStyleModelInternal.node = node;
190
+ this.forceUpdate();
181
191
  }
182
192
 
183
193
  set filter(regex: RegExp|null) {
@@ -44,7 +44,6 @@ import * as SDK from '../../core/sdk/sdk.js';
44
44
  import * as Protocol from '../../generated/protocol.js';
45
45
  import * as Badges from '../../models/badges/badges.js';
46
46
  import * as Bindings from '../../models/bindings/bindings.js';
47
- import * as ComputedStyle from '../../models/computed_style/computed_style.js';
48
47
  import * as TextUtils from '../../models/text_utils/text_utils.js';
49
48
  import * as Buttons from '../../ui/components/buttons/buttons.js';
50
49
  import * as Tooltips from '../../ui/components/tooltips/tooltips.js';
@@ -375,55 +374,12 @@ export class StylePropertiesSection {
375
374
  this.markSelectorMatches();
376
375
  this.onpopulate();
377
376
  this.#updateCollapsedState();
378
-
379
- this.stylesContainer.computedStyleModel().addEventListener(
380
- ComputedStyle.ComputedStyleModel.Events.CSS_MODEL_CHANGED, this.#onCSSModelChanged, this);
381
377
  }
382
378
 
383
379
  setComputedStyles(computedStyles: Map<string, string>|null): void {
384
380
  this.computedStyles = computedStyles;
385
381
  }
386
382
 
387
- #onCSSModelChanged(event: Common.EventTarget.EventTargetEvent<ComputedStyle.ComputedStyleModel.CSSModelChangedEvent>):
388
- void {
389
- const edit = event?.data && 'edit' in event.data ? event.data.edit : null;
390
- if (edit) {
391
- this.styleSheetEdited(edit);
392
- void this.refreshComputedValues();
393
- return;
394
- }
395
-
396
- if (this.stylesContainer.isEditingStyle || this.stylesContainer.userOperation) {
397
- void this.refreshComputedValues();
398
- }
399
- }
400
-
401
- async refreshComputedValues(): Promise<void> {
402
- const node = this.stylesContainer.node();
403
- if (!node) {
404
- return;
405
- }
406
-
407
- const cssModel = node.domModel().cssModel();
408
- const computedStyleModel = this.stylesContainer.computedStyleModel();
409
-
410
- const matchedStyles = await cssModel.cachedMatchedCascadeForNode(node);
411
- const parentNodeId = matchedStyles?.getParentLayoutNodeId();
412
-
413
- const [computedStyles, parentsComputedStyles] = await Promise.all([
414
- computedStyleModel.fetchComputedStyle(),
415
- parentNodeId ? cssModel.getComputedStyle(parentNodeId) : null,
416
- ]);
417
-
418
- if (computedStyles) {
419
- this.setComputedStyles(computedStyles.computedStyle);
420
- }
421
- if (parentsComputedStyles) {
422
- this.setParentsComputedStyles(parentsComputedStyles);
423
- }
424
- this.updateAuthoringHint();
425
- }
426
-
427
383
  setParentsComputedStyles(parentsComputedStyles: Map<string, string>|null): void {
428
384
  this.parentsComputedStyles = parentsComputedStyles;
429
385
  }
@@ -444,11 +400,6 @@ export class StylePropertiesSection {
444
400
  }
445
401
  }
446
402
 
447
- dispose(): void {
448
- this.stylesContainer.computedStyleModel().removeEventListener(
449
- ComputedStyle.ComputedStyleModel.Events.CSS_MODEL_CHANGED, this.#onCSSModelChanged, this);
450
- }
451
-
452
403
  setSectionIdx(sectionIdx: number): void {
453
404
  this.sectionIdx = sectionIdx;
454
405
  this.onpopulate();