chrome-devtools-frontend 1.0.1592362 → 1.0.1593518

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 (109) hide show
  1. package/front_end/Images/src/tab-move.svg +1 -0
  2. package/front_end/application_tokens.css +4 -4
  3. package/front_end/core/protocol_client/InspectorBackend.ts +0 -4
  4. package/front_end/core/sdk/EmulationModel.ts +1 -41
  5. package/front_end/generated/InspectorBackendCommands.ts +2 -1
  6. package/front_end/generated/SupportedCSSProperties.js +2 -2
  7. package/front_end/generated/protocol-mapping.d.ts +7 -0
  8. package/front_end/generated/protocol-proxy-api.d.ts +5 -0
  9. package/front_end/generated/protocol.ts +59 -0
  10. package/front_end/models/ai_assistance/agents/AiAgent.ts +24 -1
  11. package/front_end/models/ai_assistance/agents/BreakpointDebuggerAgent.ts +26 -86
  12. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +14 -4
  13. package/front_end/models/ai_assistance/agents/StylingAgent.ts +16 -2
  14. package/front_end/models/emulation/DeviceModeModel.ts +0 -47
  15. package/front_end/models/javascript_metadata/NativeFunctions.js +6 -6
  16. package/front_end/panels/accessibility/AXBreadcrumbsPane.ts +5 -3
  17. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +29 -6
  18. package/front_end/panels/ai_assistance/README.md +61 -0
  19. package/front_end/panels/ai_assistance/components/ChatMessage.ts +141 -27
  20. package/front_end/panels/ai_assistance/components/ChatView.ts +5 -1
  21. package/front_end/panels/ai_assistance/components/WalkthroughView.ts +19 -7
  22. package/front_end/panels/ai_assistance/components/chatMessage.css +30 -0
  23. package/front_end/panels/ai_assistance/components/walkthroughView.css +12 -7
  24. package/front_end/panels/animation/AnimationGroupPreviewUI.ts +1 -1
  25. package/front_end/panels/application/ServiceWorkerUpdateCycleView.ts +1 -0
  26. package/front_end/panels/application/components/BackForwardCacheView.ts +4 -2
  27. package/front_end/panels/autofill/AutofillView.ts +1 -1
  28. package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +161 -154
  29. package/front_end/panels/browser_debugger/XHRBreakpointsSidebarPane.ts +1 -0
  30. package/front_end/panels/browser_debugger/domBreakpointsSidebarPane.css +58 -36
  31. package/front_end/panels/console/ConsoleViewMessage.ts +1 -0
  32. package/front_end/panels/console/consoleView.css +7 -2
  33. package/front_end/panels/elements/ComputedStyleWidget.ts +5 -1
  34. package/front_end/panels/elements/ElementsTreeElement.ts +1 -0
  35. package/front_end/panels/elements/LayoutPane.ts +8 -7
  36. package/front_end/panels/elements/StandaloneStylesContainer.ts +254 -0
  37. package/front_end/panels/elements/components/ComputedStyleTrace.ts +4 -0
  38. package/front_end/panels/elements/components/ElementsBreadcrumbs.ts +1 -1
  39. package/front_end/panels/elements/components/StylePropertyEditor.ts +2 -1
  40. package/front_end/panels/elements/components/computedStyleProperty.css +1 -1
  41. package/front_end/panels/elements/elements.ts +2 -0
  42. package/front_end/panels/emulation/DeviceModeToolbar.ts +0 -25
  43. package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +1 -1
  44. package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +1 -1
  45. package/front_end/panels/linear_memory_inspector/components/ValueInterpreterDisplay.ts +1 -1
  46. package/front_end/panels/media/PlayerListView.ts +1 -1
  47. package/front_end/panels/network/NetworkLogViewColumns.ts +2 -1
  48. package/front_end/panels/network/components/RequestHeaderSection.ts +1 -1
  49. package/front_end/panels/protocol_monitor/JSONEditor.ts +1 -1
  50. package/front_end/panels/recorder/components/RecordingListView.ts +1 -1
  51. package/front_end/panels/recorder/components/StepEditor.ts +3 -3
  52. package/front_end/panels/settings/KeybindsSettingsTab.ts +2 -1
  53. package/front_end/panels/sources/components/HeadersView.ts +2 -2
  54. package/front_end/panels/timeline/components/BreadcrumbsUI.ts +1 -1
  55. package/front_end/panels/timeline/components/SidebarAnnotationsTab.ts +1 -1
  56. package/front_end/third_party/chromium/README.chromium +1 -1
  57. package/front_end/third_party/puppeteer/README.chromium +2 -2
  58. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Navigation.d.ts.map +1 -1
  59. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Navigation.js +1 -0
  60. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Navigation.js.map +1 -1
  61. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.js +1 -1
  62. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/BrowserContext.js.map +1 -1
  63. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +1 -1
  64. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
  65. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  66. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
  67. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js +1 -0
  68. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js.map +1 -1
  69. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
  70. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
  71. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  72. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  73. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  74. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  75. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +6 -6
  76. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Navigation.d.ts.map +1 -1
  77. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Navigation.js +1 -0
  78. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Navigation.js.map +1 -1
  79. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.js +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/BrowserContext.js.map +1 -1
  81. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
  83. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
  84. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js +1 -0
  85. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js.map +1 -1
  86. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
  87. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
  88. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  89. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  90. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  91. package/front_end/third_party/puppeteer/package/package.json +4 -4
  92. package/front_end/third_party/puppeteer/package/src/bidi/core/Navigation.ts +1 -0
  93. package/front_end/third_party/puppeteer/package/src/cdp/BrowserContext.ts +1 -1
  94. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +1 -1
  95. package/front_end/third_party/puppeteer/package/src/node/ChromeLauncher.ts +1 -0
  96. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  97. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  98. package/front_end/ui/components/suggestion_input/SuggestionInput.ts +7 -12
  99. package/front_end/ui/components/tree_outline/TreeOutline.ts +6 -2
  100. package/front_end/ui/components/tree_outline/treeOutline.css +5 -0
  101. package/front_end/ui/legacy/ListControl.ts +5 -3
  102. package/front_end/ui/legacy/ListWidget.ts +1 -1
  103. package/front_end/ui/legacy/SoftContextMenu.ts +2 -1
  104. package/front_end/ui/legacy/Treeoutline.ts +1 -0
  105. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +4 -2
  106. package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +1 -1
  107. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +31 -0
  108. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  109. package/package.json +1 -1
@@ -333,6 +333,7 @@
333
333
  }
334
334
  }
335
335
 
336
+
336
337
  .error-step {
337
338
  color: var(--sys-color-error);
338
339
  }
@@ -354,4 +355,33 @@
354
355
  gap: var(--sys-size-4);
355
356
  align-items: center;
356
357
  }
358
+
359
+
360
+ .computed-styles-widget {
361
+ display: block;
362
+ width: fit-content;
363
+ }
364
+
365
+ .step-widgets-wrapper {
366
+ width: fit-content;
367
+ }
368
+
369
+ .widget-reveal-container {
370
+ width: 100%;
371
+ background: var(--sys-color-surface5);
372
+ border-bottom-right-radius: var(--sys-shape-corner-medium);
373
+ border-bottom-left-radius: var(--sys-shape-corner-medium);
374
+ padding: 0 var(--sys-size-4) var(--sys-size-4) 0;
375
+ }
376
+
377
+ .widget-content-container {
378
+ padding: var(--sys-size-4);
379
+ border-top-left-radius: var(--sys-shape-corner-medium);
380
+ border-top-right-radius: var(--sys-shape-corner-medium);
381
+ width: 100%;
382
+ overflow-x: auto;
383
+ background-color: var(--sys-color-surface3);
384
+
385
+ --override-computed-style-property-white-space: normal;
386
+ }
357
387
  }
@@ -78,26 +78,31 @@
78
78
  border-radius: var(--sys-size-5);
79
79
  overflow: hidden;
80
80
  background-color: var(--sys-color-surface1);
81
+ width: fit-content;
82
+
83
+ &[open] {
84
+ width: auto;
85
+ }
81
86
  }
82
87
 
83
- .walkthrough-inline summary {
88
+ .walkthrough-inline > summary {
84
89
  display: flex;
85
90
  align-items: center;
86
- justify-content: space-between;
87
- padding: var(--sys-size-5) var(--sys-size-6);
91
+ padding: var(--sys-size-4) var(--sys-size-6);
88
92
  cursor: pointer;
89
93
  background-color: transparent;
90
- font-weight: 500;
91
- font-size: 11px;
94
+ font: var(--sys-typescale-body4-regular);
92
95
  user-select: none;
93
96
  list-style: none; /* Hide default triangle */
97
+ justify-content: flex-start;
98
+ gap: var(--sys-size-4);
94
99
  }
95
100
 
96
- .walkthrough-inline summary::-webkit-details-marker {
101
+ .walkthrough-inline > summary::-webkit-details-marker {
97
102
  display: none;
98
103
  }
99
104
 
100
- .walkthrough-inline summary:hover {
105
+ .walkthrough-inline > summary:hover {
101
106
  background-color: var(--sys-color-state-hover-on-subtle);
102
107
  }
103
108
 
@@ -98,7 +98,7 @@ const DEFAULT_VIEW: View = (input, output, target) => {
98
98
  render(html`
99
99
  <div class="animation-group-preview-ui">
100
100
  <button
101
- jslog=${VisualLogging.item(`animations.buffer-preview${input.isScrollDrivenAnimationGroup ? '-sda' : ''}`).track({click: true})}
101
+ jslog=${VisualLogging.item(`animations.buffer-preview${input.isScrollDrivenAnimationGroup ? '-sda' : ''}`).track({click: true, resize: true})}
102
102
  class=${classes}
103
103
  role="option"
104
104
  aria-label=${input.label}
@@ -180,6 +180,7 @@ export class ServiceWorkerUpdateCycleView {
180
180
  const tr = this.tableElement.createChild('tr', 'service-worker-update-timeline');
181
181
  tr.setAttribute('jslog', `${VisualLogging.treeItem('update-timeline').track({
182
182
  click: true,
183
+ resize: true,
183
184
  keydown: 'ArrowLeft|ArrowRight|ArrowUp|ArrowDown|Enter|Space',
184
185
  })}`);
185
186
  this.rows.push(tr);
@@ -353,7 +353,7 @@ function renderFramesPerReason(frames: string[]|undefined): LitTemplate {
353
353
  }
354
354
  const rows = [html`<div>${i18nString(UIStrings.framesPerIssue, {n: frames.length})}</div>`];
355
355
  rows.push(...frames.map(url => html`<div class="text-ellipsis" title=${url}
356
- jslog=${VisualLogging.treeItem()}>${url}</div>`));
356
+ jslog=${VisualLogging.treeItem().track({resize: true})}>${url}</div>`));
357
357
  return html`
358
358
  <div class="details-list"
359
359
  jslog=${VisualLogging.tree('frames-per-issue')}>
@@ -361,7 +361,9 @@ function renderFramesPerReason(frames: string[]|undefined): LitTemplate {
361
361
  rows,
362
362
  title: i18nString(UIStrings.framesPerIssue, {n: frames.length}),
363
363
  } as ExpandableList.ExpandableList.ExpandableListData}
364
- jslog=${VisualLogging.treeItem()}></devtools-expandable-list>
364
+ jslog=${VisualLogging.treeItem().track({
365
+ resize: true
366
+ })}></devtools-expandable-list>
365
367
  </div>
366
368
  `;
367
369
  }
@@ -144,7 +144,7 @@ const DEFAULT_VIEW: View = (input: ViewInput, _output: ViewOutput, target: HTMLE
144
144
  // clang-format off
145
145
  return html`
146
146
  <span class=${spanClasses}
147
- jslog=${VisualLogging.item('matched-address-item').track({hover: true})}
147
+ jslog=${VisualLogging.item('matched-address-item').track({hover: true, resize: true})}
148
148
  @mouseenter=${() => input.onHighlightMatchesInAddress(startIndex)}
149
149
  @mouseleave=${input.onClearHighlightedMatches}>
150
150
  ${templateLines}
@@ -2,14 +2,13 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
- /* eslint-disable @devtools/no-imperative-dom-api */
6
-
7
5
  import * as Common from '../../core/common/common.js';
8
6
  import * as i18n from '../../core/i18n/i18n.js';
9
7
  import type * as Platform from '../../core/platform/platform.js';
10
8
  import * as SDK from '../../core/sdk/sdk.js';
11
9
  import * as Protocol from '../../generated/protocol.js';
12
10
  import * as UI from '../../ui/legacy/legacy.js';
11
+ import * as Lit from '../../ui/lit/lit.js';
13
12
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
14
13
  import * as PanelsCommon from '../common/common.js';
15
14
  import * as Sources from '../sources/sources.js';
@@ -107,38 +106,118 @@ const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined
107
106
  const DOM_BREAKPOINT_DOCUMENTATION_URL =
108
107
  'https://developer.chrome.com/docs/devtools/javascript/breakpoints#dom' as Platform.DevToolsPath.UrlString;
109
108
 
109
+ const {html, render, Directives} = Lit;
110
+
111
+ export interface Breakpoint {
112
+ breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint;
113
+ label: string;
114
+ isHighlighted: boolean;
115
+ isFocused: boolean;
116
+ }
117
+
118
+ export interface ViewInput {
119
+ breakpoints: Breakpoint[];
120
+ onBreakpointClick: (breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint) => void;
121
+ onBreakpointCheckboxClick: (breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint) => void;
122
+ onBreakpointContextMenu: (breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint, event: Event) => void;
123
+ onBreakpointKeyDown: (breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint, event: Event) => void;
124
+ }
125
+
126
+ export type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
127
+
128
+ export const DEFAULT_VIEW: View = (input, _output, target) => {
129
+ const hasBreakpoints = input.breakpoints.length > 0;
130
+
131
+ // clang-format off
132
+ render(
133
+ html`
134
+ <style>${domBreakpointsSidebarPaneStyles}</style>
135
+ <div class="dom-breakpoints-container" jslog=${VisualLogging.section('sources.dom-breakpoints').track({ resize: true })}>
136
+ ${hasBreakpoints ? html
137
+ `<ul class="breakpoint-list"
138
+ aria-label=${i18nString(UIStrings.domBreakpointsList)}>
139
+ ${input.breakpoints.map(item => {
140
+ const {breakpoint} = item;
141
+ const checkedStateText = breakpoint.enabled ? i18nString(UIStrings.checked) : i18nString(UIStrings.unchecked);
142
+ const linkified = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(
143
+ breakpoint.node, {preventKeyboardFocus: true, tooltip: undefined});
144
+ return html`
145
+ <li class=${`breakpoint-entry ${item.isHighlighted ? 'breakpoint-hit' : ''}`}
146
+ tabindex=${item.isFocused ? '0' : '-1'}
147
+ @click=${() => input.onBreakpointClick(breakpoint)}
148
+ @contextmenu=${(e: Event) => input.onBreakpointContextMenu(breakpoint, e)}
149
+ @keydown=${(e: Event) => input.onBreakpointKeyDown(breakpoint, e)}
150
+ aria-label=${i18nString(UIStrings.sSS, { PH1: item.label, PH2: linkified.deepTextContent(), PH3: checkedStateText })}
151
+ aria-description=${item.isHighlighted ? i18nString(UIStrings.sBreakpointHit, { PH1: checkedStateText }) : checkedStateText}
152
+ jslog=${VisualLogging.domBreakpoint().context(breakpoint.type).track({ keydown: 'ArrowUp|ArrowDown|PageUp|PageDown' })}>
153
+ <devtools-checkbox
154
+ class="checkbox-label"
155
+ .checked=${breakpoint.enabled}
156
+ @click=${(e: Event) => e.stopPropagation()}
157
+ @change=${() => input.onBreakpointCheckboxClick(breakpoint)}
158
+ tabindex="-1"
159
+ aria-label=${i18nString(UIStrings.sS, { PH1: item.label, PH2: linkified.deepTextContent() })}
160
+ aria-description=${Directives.ifDefined(item.isHighlighted ? i18nString(UIStrings.breakpointHit) : undefined)}
161
+ jslog=${VisualLogging.toggle().track({ click: true })}>
162
+ </devtools-checkbox>
163
+ <div class="dom-breakpoint">
164
+ <code class="monospace" style="display: block;">${linkified}</code>
165
+ <div>${item.label}</div>
166
+ </div>
167
+ </li>`;
168
+ })}
169
+ </ul>` : html
170
+ `<div class="placeholder">
171
+ <div class="gray-info-message">${i18nString(UIStrings.noBreakpoints)}</div>
172
+ <devtools-widget .widgetConfig=${UI.Widget.widgetConfig(UI.EmptyWidget.EmptyWidget, {
173
+ header: i18nString(UIStrings.noBreakpoints),
174
+ text: i18nString(UIStrings.domBreakpointsDescription),
175
+ link: DOM_BREAKPOINT_DOCUMENTATION_URL,
176
+ })}></devtools-widget>
177
+ </div>`}
178
+ </div>
179
+ `,
180
+ target
181
+ );
182
+ // clang-format on
183
+ };
184
+
110
185
  let domBreakpointsSidebarPaneInstance: DOMBreakpointsSidebarPane;
111
186
 
112
187
  export class DOMBreakpointsSidebarPane extends UI.Widget.VBox implements
113
- UI.ContextFlavorListener.ContextFlavorListener, UI.ListControl.ListDelegate<SDK.DOMDebuggerModel.DOMBreakpoint> {
114
- elementToCheckboxes: WeakMap<Element, UI.UIUtils.CheckboxLabel>;
115
- readonly #emptyElement: HTMLElement;
116
- readonly #breakpoints: UI.ListModel.ListModel<SDK.DOMDebuggerModel.DOMBreakpoint>;
117
- #list: UI.ListControl.ListControl<SDK.DOMDebuggerModel.DOMBreakpoint>;
118
- #highlightedBreakpoint: SDK.DOMDebuggerModel.DOMBreakpoint|null;
119
-
120
- private constructor() {
188
+ UI.ContextFlavorListener.ContextFlavorListener {
189
+ readonly #breakpoints: SDK.DOMDebuggerModel.DOMBreakpoint[] = [];
190
+ #highlightedBreakpoint: SDK.DOMDebuggerModel.DOMBreakpoint|null = null;
191
+ #focusedBreakpoint: SDK.DOMDebuggerModel.DOMBreakpoint|null = null;
192
+ readonly #view: View;
193
+
194
+ set highlightedBreakpoint(breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint|null) {
195
+ this.#highlightedBreakpoint = breakpoint;
196
+ this.requestUpdate();
197
+ }
198
+
199
+ set focusedBreakpoint(breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint|null) {
200
+ if (this.#focusedBreakpoint === breakpoint) {
201
+ return;
202
+ }
203
+ this.#focusedBreakpoint = breakpoint;
204
+ this.#synchronizeFocusedBreakpoint();
205
+ this.requestUpdate();
206
+ }
207
+
208
+ #synchronizeFocusedBreakpoint(): void {
209
+ if (this.#focusedBreakpoint && !this.#breakpoints.includes(this.#focusedBreakpoint)) {
210
+ this.#focusedBreakpoint = null;
211
+ }
212
+ if (!this.#focusedBreakpoint && this.#breakpoints.length > 0) {
213
+ this.#focusedBreakpoint = this.#breakpoints[0];
214
+ }
215
+ }
216
+
217
+ constructor(view = DEFAULT_VIEW) {
121
218
  super({useShadowDom: true});
122
- this.registerRequiredCSS(domBreakpointsSidebarPaneStyles);
123
-
124
- this.elementToCheckboxes = new WeakMap();
125
-
126
- this.contentElement.setAttribute(
127
- 'jslog', `${VisualLogging.section('sources.dom-breakpoints').track({resize: true})}`);
128
- this.contentElement.classList.add('dom-breakpoints-container');
129
- this.#emptyElement = this.contentElement.createChild('div', 'placeholder');
130
- this.#emptyElement.createChild('div', 'gray-info-message').textContent = i18nString(UIStrings.noBreakpoints);
131
- const emptyWidget =
132
- new UI.EmptyWidget.EmptyWidget(UIStrings.noBreakpoints, i18nString(UIStrings.domBreakpointsDescription));
133
- emptyWidget.link = DOM_BREAKPOINT_DOCUMENTATION_URL;
134
- emptyWidget.show(this.#emptyElement);
135
-
136
- this.#breakpoints = new UI.ListModel.ListModel();
137
- this.#list = new UI.ListControl.ListControl(this.#breakpoints, this, UI.ListControl.ListMode.NonViewport);
138
- this.contentElement.appendChild(this.#list.element);
139
- this.#list.element.classList.add('breakpoint-list', 'hidden');
140
- UI.ARIAUtils.markAsList(this.#list.element);
141
- UI.ARIAUtils.setLabel(this.#list.element, i18nString(UIStrings.domBreakpointsList));
219
+
220
+ this.#view = view;
142
221
 
143
222
  SDK.TargetManager.TargetManager.instance().addModelListener(
144
223
  SDK.DOMDebuggerModel.DOMDebuggerModel, SDK.DOMDebuggerModel.Events.DOM_BREAKPOINT_ADDED, this.breakpointAdded,
@@ -158,7 +237,6 @@ export class DOMBreakpointsSidebarPane extends UI.Widget.VBox implements
158
237
  }
159
238
  }
160
239
 
161
- this.#highlightedBreakpoint = null;
162
240
  this.update();
163
241
  }
164
242
 
@@ -169,93 +247,41 @@ export class DOMBreakpointsSidebarPane extends UI.Widget.VBox implements
169
247
  return domBreakpointsSidebarPaneInstance;
170
248
  }
171
249
 
172
- createElementForItem(item: SDK.DOMDebuggerModel.DOMBreakpoint): Element {
173
- const element = document.createElement('div');
174
- element.classList.add('breakpoint-entry');
175
- element.setAttribute(
176
- 'jslog',
177
- `${VisualLogging.domBreakpoint().context(item.type).track({keydown: 'ArrowUp|ArrowDown|PageUp|PageDown'})}`);
178
- element.addEventListener('contextmenu', this.contextMenu.bind(this, item), true);
179
- UI.ARIAUtils.markAsListitem(element);
180
- element.tabIndex = -1;
181
-
182
- const checkbox = UI.UIUtils.CheckboxLabel.create(/* title */ undefined, item.enabled);
183
- checkbox.addEventListener('click', this.checkboxClicked.bind(this, item), false);
184
- checkbox.tabIndex = -1;
185
- this.elementToCheckboxes.set(element, checkbox);
186
- element.appendChild(checkbox);
187
- element.addEventListener('keydown', event => {
188
- if (event.key === ' ') {
189
- checkbox.click();
190
- event.consume(true);
191
- }
192
- });
193
-
194
- const labelElement = document.createElement('div');
195
- labelElement.classList.add('dom-breakpoint');
196
- element.appendChild(labelElement);
197
- const description = document.createElement('div');
198
- const breakpointTypeLabel = BreakpointTypeLabels.get(item.type);
199
- description.textContent = breakpointTypeLabel ? breakpointTypeLabel() : null;
200
- const breakpointTypeText = breakpointTypeLabel ? breakpointTypeLabel() : '';
201
- UI.ARIAUtils.setLabel(checkbox, breakpointTypeText);
202
- checkbox.setAttribute('jslog', `${VisualLogging.toggle().track({click: true})}`);
203
- const checkedStateText = item.enabled ? i18nString(UIStrings.checked) : i18nString(UIStrings.unchecked);
204
- const linkifiedNode = document.createElement('monospace');
205
- linkifiedNode.style.display = 'block';
206
- labelElement.appendChild(linkifiedNode);
207
- const linkified = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(
208
- item.node, {preventKeyboardFocus: true, tooltip: undefined});
209
- linkifiedNode.appendChild(linkified);
210
- // Give the checkbox an aria-label as it is required for all form element
211
- UI.ARIAUtils.setLabel(
212
- checkbox, i18nString(UIStrings.sS, {PH1: breakpointTypeText, PH2: linkified.deepTextContent()}));
213
- // The parent list element is the one that actually gets focused.
214
- // Assign it an aria-label with complete information for the screen reader to read out properly
215
- UI.ARIAUtils.setLabel(
216
- element,
217
- i18nString(UIStrings.sSS, {PH1: breakpointTypeText, PH2: linkified.deepTextContent(), PH3: checkedStateText}));
218
-
219
- labelElement.appendChild(description);
220
-
221
- if (item === this.#highlightedBreakpoint) {
222
- element.classList.add('breakpoint-hit');
223
- UI.ARIAUtils.setDescription(element, i18nString(UIStrings.sBreakpointHit, {PH1: checkedStateText}));
224
- UI.ARIAUtils.setDescription(checkbox, i18nString(UIStrings.breakpointHit));
225
- } else {
226
- UI.ARIAUtils.setDescription(element, checkedStateText);
227
- }
228
-
229
- this.#emptyElement.classList.add('hidden');
230
- this.#list.element.classList.remove('hidden');
231
-
232
- return element;
233
- }
234
-
235
- heightForItem(_item: SDK.DOMDebuggerModel.DOMBreakpoint): number {
236
- return 0;
237
- }
238
-
239
- isItemSelectable(_item: SDK.DOMDebuggerModel.DOMBreakpoint): boolean {
240
- return true;
250
+ override performUpdate(): void {
251
+ const input: ViewInput = {
252
+ breakpoints: this.#breakpoints.map(breakpoint => ({
253
+ breakpoint,
254
+ label: BreakpointTypeLabels.get(breakpoint.type)?.() ?? '',
255
+ isHighlighted: breakpoint === this.#highlightedBreakpoint,
256
+ isFocused: breakpoint === this.#focusedBreakpoint,
257
+ })),
258
+ onBreakpointClick: this.onBreakpointClick.bind(this),
259
+ onBreakpointCheckboxClick: this.onBreakpointCheckboxClick.bind(this),
260
+ onBreakpointContextMenu: this.onBreakpointContextMenu.bind(this),
261
+ onBreakpointKeyDown: this.onBreakpointKeyDown.bind(this),
262
+ };
263
+ this.#view(input, undefined, this.contentElement);
241
264
  }
242
265
 
243
- updateSelectedItemARIA(_fromElement: Element|null, _toElement: Element|null): boolean {
244
- return true;
266
+ private onBreakpointClick(breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint): void {
267
+ this.focusedBreakpoint = breakpoint;
245
268
  }
246
269
 
247
- selectedItemChanged(
248
- _from: SDK.DOMDebuggerModel.DOMBreakpoint|null, _to: SDK.DOMDebuggerModel.DOMBreakpoint|null,
249
- fromElement: HTMLElement|null, toElement: HTMLElement|null): void {
250
- if (fromElement) {
251
- fromElement.tabIndex = -1;
252
- }
253
-
254
- if (toElement) {
255
- this.setDefaultFocusedElement(toElement);
256
- toElement.tabIndex = 0;
257
- if (this.hasFocus()) {
258
- toElement.focus();
270
+ private onBreakpointKeyDown(breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint, event: Event): void {
271
+ const keyboardEvent = event as KeyboardEvent;
272
+ if (keyboardEvent.key === ' ') {
273
+ this.onBreakpointCheckboxClick(breakpoint);
274
+ keyboardEvent.consume(true);
275
+ } else if (keyboardEvent.key === 'ArrowUp' || keyboardEvent.key === 'ArrowDown') {
276
+ const index = this.#breakpoints.indexOf(breakpoint);
277
+ const newIndex = keyboardEvent.key === 'ArrowUp' ? index - 1 : index + 1;
278
+ if (newIndex >= 0 && newIndex < this.#breakpoints.length) {
279
+ this.focusedBreakpoint = this.#breakpoints[newIndex];
280
+ void this.updateComplete.then(() => {
281
+ const entry = this.contentElement.querySelectorAll('.breakpoint-entry')[newIndex] as HTMLElement;
282
+ entry.focus();
283
+ });
284
+ keyboardEvent.consume(true);
259
285
  }
260
286
  }
261
287
  }
@@ -264,43 +290,28 @@ export class DOMBreakpointsSidebarPane extends UI.Widget.VBox implements
264
290
  this.addBreakpoint(event.data);
265
291
  }
266
292
 
267
- private breakpointToggled(event: Common.EventTarget.EventTargetEvent<SDK.DOMDebuggerModel.DOMBreakpoint>): void {
268
- const hadFocus = this.hasFocus();
269
- const breakpoint = event.data;
270
- this.#list.refreshItem(breakpoint);
271
- if (hadFocus) {
272
- this.focus();
273
- }
293
+ private breakpointToggled(_event: Common.EventTarget.EventTargetEvent<SDK.DOMDebuggerModel.DOMBreakpoint>): void {
294
+ this.requestUpdate();
274
295
  }
275
296
 
276
297
  private breakpointsRemoved(event: Common.EventTarget.EventTargetEvent<SDK.DOMDebuggerModel.DOMBreakpoint[]>): void {
277
- const hadFocus = this.hasFocus();
278
298
  const breakpoints = event.data;
279
- let lastIndex = -1;
280
299
  for (const breakpoint of breakpoints) {
281
300
  const index = this.#breakpoints.indexOf(breakpoint);
282
301
  if (index >= 0) {
283
- this.#breakpoints.remove(index);
284
- lastIndex = index;
302
+ this.#breakpoints.splice(index, 1);
285
303
  }
286
304
  }
287
- if (this.#breakpoints.length === 0) {
288
- this.#emptyElement.classList.remove('hidden');
289
- this.setDefaultFocusedElement(this.#emptyElement);
290
- this.#list.element.classList.add('hidden');
291
- } else if (lastIndex >= 0) {
292
- const breakpointToSelect = this.#breakpoints.at(lastIndex);
293
- if (breakpointToSelect) {
294
- this.#list.selectItem(breakpointToSelect);
295
- }
296
- }
297
- if (hadFocus) {
298
- this.focus();
299
- }
305
+ this.#synchronizeFocusedBreakpoint();
306
+ this.requestUpdate();
300
307
  }
301
308
 
302
309
  private addBreakpoint(breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint): void {
303
- this.#breakpoints.insertWithComparator(breakpoint, (breakpointA, breakpointB) => {
310
+ if (this.#breakpoints.includes(breakpoint)) {
311
+ return;
312
+ }
313
+ this.#breakpoints.push(breakpoint);
314
+ this.#breakpoints.sort((breakpointA, breakpointB) => {
304
315
  if (breakpointA.type > breakpointB.type) {
305
316
  return -1;
306
317
  }
@@ -309,12 +320,12 @@ export class DOMBreakpointsSidebarPane extends UI.Widget.VBox implements
309
320
  }
310
321
  return 0;
311
322
  });
312
- if (!this.#list.selectedItem() || !this.hasFocus()) {
313
- this.#list.selectItem(this.#breakpoints.at(0));
314
- }
323
+ this.#synchronizeFocusedBreakpoint();
324
+ this.requestUpdate();
315
325
  }
316
326
 
317
- private contextMenu(breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint, event: Event): void {
327
+ private onBreakpointContextMenu(breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint, event: Event): void {
328
+ this.focusedBreakpoint = breakpoint;
318
329
  const contextMenu = new UI.ContextMenu.ContextMenu(event);
319
330
  contextMenu.defaultSection().appendItem(
320
331
  i18nString(UIStrings.revealDomNodeInElementsPanel), () => Common.Revealer.reveal(breakpoint.node),
@@ -328,9 +339,9 @@ export class DOMBreakpointsSidebarPane extends UI.Widget.VBox implements
328
339
  void contextMenu.show();
329
340
  }
330
341
 
331
- private checkboxClicked(breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint, event: Event): void {
332
- breakpoint.domDebuggerModel.toggleDOMBreakpoint(
333
- breakpoint, event.target ? (event.target as HTMLInputElement).checked : false);
342
+ private onBreakpointCheckboxClick(breakpoint: SDK.DOMDebuggerModel.DOMBreakpoint): void {
343
+ this.focusedBreakpoint = breakpoint;
344
+ breakpoint.domDebuggerModel.toggleDOMBreakpoint(breakpoint, !breakpoint.enabled);
334
345
  }
335
346
 
336
347
  flavorChanged(_object: Object|null): void {
@@ -339,11 +350,7 @@ export class DOMBreakpointsSidebarPane extends UI.Widget.VBox implements
339
350
 
340
351
  update(): void {
341
352
  const details = UI.Context.Context.instance().flavor(SDK.DebuggerModel.DebuggerPausedDetails);
342
- if (this.#highlightedBreakpoint) {
343
- const oldHighlightedBreakpoint = this.#highlightedBreakpoint;
344
- this.#highlightedBreakpoint = null;
345
- this.#list.refreshItem(oldHighlightedBreakpoint);
346
- }
353
+ this.highlightedBreakpoint = null;
347
354
  if (!details?.auxData || details.reason !== Protocol.Debugger.PausedEventReason.DOM) {
348
355
  return;
349
356
  }
@@ -361,13 +368,13 @@ export class DOMBreakpointsSidebarPane extends UI.Widget.VBox implements
361
368
 
362
369
  for (const breakpoint of this.#breakpoints) {
363
370
  if (breakpoint.node === data.node && breakpoint.type === data.type) {
364
- this.#highlightedBreakpoint = breakpoint;
371
+ this.highlightedBreakpoint = breakpoint;
372
+ this.focusedBreakpoint = breakpoint;
365
373
  }
366
374
  }
367
375
  if (this.#highlightedBreakpoint) {
368
- this.#list.refreshItem(this.#highlightedBreakpoint);
376
+ void UI.ViewManager.ViewManager.instance().showView('sources.dom-breakpoints');
369
377
  }
370
- void UI.ViewManager.ViewManager.instance().showView('sources.dom-breakpoints');
371
378
  }
372
379
  }
373
380
 
@@ -238,6 +238,7 @@ export class XHRBreakpointsSidebarPane extends UI.Widget.VBox implements UI.Cont
238
238
  listItemElement.setAttribute('jslog', `${VisualLogging.item().track({
239
239
  click: true,
240
240
  dblclick: true,
241
+ resize: true,
241
242
  keydown: 'ArrowUp|ArrowDown|PageUp|PageDown|Enter|Space',
242
243
  })}`);
243
244
  return listItemElement;
@@ -4,40 +4,60 @@
4
4
  * found in the LICENSE file.
5
5
  */
6
6
 
7
- .dom-breakpoints-container {
8
- overflow: auto;
9
- }
7
+ @scope to (devtools-widget > *) {
8
+ :scope {
9
+ overflow: auto;
10
+ }
10
11
 
11
- .breakpoint-list {
12
- padding-bottom: 3px;
13
- }
12
+ .monospace {
13
+ font-family: var(--monospace-font-family);
14
+ font-size: var(--monospace-font-size);
15
+ }
14
16
 
15
- .breakpoint-list .dom-breakpoint > div {
16
- overflow: hidden;
17
- text-overflow: ellipsis;
18
- }
17
+ .dom-breakpoints-container {
18
+ flex-grow: 1;
19
+ }
19
20
 
20
- .breakpoint-entry {
21
- display: flex;
22
- white-space: nowrap;
23
- text-overflow: ellipsis;
24
- overflow: hidden;
25
- padding: 2px 0;
26
- }
21
+ .breakpoint-list {
22
+ padding: 0 0 3px;
23
+ list-style-type: none;
24
+ margin: 0;
25
+ }
27
26
 
28
- .breakpoint-entry:focus-visible {
29
- background-color: var(--sys-color-tonal-container);
30
- }
27
+ .breakpoint-list .dom-breakpoint > div {
28
+ overflow: hidden;
29
+ text-overflow: ellipsis;
30
+ }
31
31
 
32
- .breakpoint-hit {
33
- background-color: var(--sys-color-neutral-container);
34
- color: var(--sys-color-on-surface);
35
- }
32
+ .breakpoint-entry {
33
+ display: flex;
34
+ white-space: nowrap;
35
+ text-overflow: ellipsis;
36
+ overflow: hidden;
37
+ padding: 2px 0;
38
+ }
39
+
40
+ .breakpoint-entry:focus-visible {
41
+ background-color: var(--sys-color-tonal-container);
42
+ }
43
+
44
+ .breakpoint-hit {
45
+ background-color: var(--sys-color-neutral-container);
46
+ color: var(--sys-color-on-surface);
47
+ }
48
+
49
+ .placeholder {
50
+ display: flex;
51
+ height: 100%;
52
+ justify-content: center;
53
+ }
36
54
 
37
- .placeholder {
38
- display: flex;
39
- height: 100%;
40
- justify-content: center;
55
+ .gray-info-message {
56
+ display: flex;
57
+ justify-content: center;
58
+ align-items: center;
59
+ padding: 20px;
60
+ }
41
61
  }
42
62
 
43
63
  :host-context(.sources.panel) .empty-view-scroller {
@@ -49,14 +69,16 @@
49
69
  }
50
70
 
51
71
  @media (forced-colors: active) {
52
- .breakpoint-entry:focus-visible,
53
- .breakpoint-list .breakpoint-entry:hover {
54
- forced-color-adjust: none;
55
- background-color: Highlight;
56
- }
72
+ @scope to (devtools-widget > *) {
73
+ .breakpoint-entry:focus-visible,
74
+ .breakpoint-list .breakpoint-entry:hover {
75
+ forced-color-adjust: none;
76
+ background-color: Highlight;
77
+ }
57
78
 
58
- .breakpoint-entry:focus-visible *,
59
- .breakpoint-list .breakpoint-entry:hover * {
60
- color: HighlightText;
79
+ .breakpoint-entry:focus-visible *,
80
+ .breakpoint-list .breakpoint-entry:hover * {
81
+ color: HighlightText;
82
+ }
61
83
  }
62
84
  }