chrome-devtools-frontend 1.0.1587572 → 1.0.1588580

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 (42) hide show
  1. package/front_end/core/sdk/DOMModel.ts +3 -0
  2. package/front_end/core/sdk/PreloadingModel.ts +15 -6
  3. package/front_end/core/sdk/ScopeTreeCache.ts +4 -0
  4. package/front_end/generated/Deprecation.ts +21 -0
  5. package/front_end/generated/InspectorBackendCommands.ts +5 -3
  6. package/front_end/generated/SupportedCSSProperties.js +46 -0
  7. package/front_end/generated/protocol-mapping.d.ts +4 -0
  8. package/front_end/generated/protocol-proxy-api.d.ts +5 -0
  9. package/front_end/generated/protocol.ts +49 -0
  10. package/front_end/models/ai_assistance/AiConversation.ts +5 -1
  11. package/front_end/models/ai_assistance/agents/AiAgent.ts +16 -4
  12. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +7 -1
  13. package/front_end/models/computed_style/ComputedStyleModel.ts +2 -1
  14. package/front_end/models/javascript_metadata/NativeFunctions.js +4 -16
  15. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +15 -23
  16. package/front_end/panels/ai_assistance/components/ChatInput.ts +36 -31
  17. package/front_end/panels/ai_assistance/components/chatInput.css +6 -9
  18. package/front_end/panels/application/ServiceWorkerCacheViews.ts +3 -5
  19. package/front_end/panels/application/preloading/PreloadingView.ts +18 -0
  20. package/front_end/panels/application/preloading/components/RuleSetDetailsView.css +12 -0
  21. package/front_end/panels/application/preloading/components/RuleSetDetailsView.ts +3 -3
  22. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +11 -3
  23. package/front_end/panels/common/DOMLinkifier.ts +6 -1
  24. package/front_end/panels/console/ConsoleViewMessage.ts +3 -3
  25. package/front_end/panels/elements/ColorSwatchPopoverIcon.ts +1 -1
  26. package/front_end/panels/elements/ComputedStyleWidget.ts +27 -18
  27. package/front_end/panels/elements/ElementsPanel.ts +12 -4
  28. package/front_end/panels/elements/PropertiesWidget.ts +91 -52
  29. package/front_end/panels/elements/StylePropertyTreeElement.ts +11 -12
  30. package/front_end/panels/elements/StylesSidebarPane.ts +51 -8
  31. package/front_end/panels/elements/elementsPanel.css +6 -2
  32. package/front_end/panels/network/NetworkDataGridNode.ts +4 -0
  33. package/front_end/panels/network/NetworkItemView.ts +6 -45
  34. package/front_end/panels/network/RequestHeadersView.ts +237 -318
  35. package/front_end/panels/sources/CSSPlugin.ts +1 -1
  36. package/front_end/third_party/chromium/README.chromium +1 -1
  37. package/front_end/ui/legacy/Toolbar.ts +37 -5
  38. package/front_end/ui/legacy/UIUtils.ts +35 -5
  39. package/front_end/ui/legacy/components/inline_editor/ColorSwatch.ts +32 -28
  40. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +31 -6
  41. package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
  42. package/package.json +1 -1
@@ -202,7 +202,8 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
202
202
  jslog=${VisualLogging.link('open-ai-settings').track({
203
203
  click: true,
204
204
  })}
205
- @click=${() => {
205
+ @click=${(ev: Event) => {
206
+ ev.preventDefault();
206
207
  void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
207
208
  }}
208
209
  >${lockedString('Relevant data')}</button>&nbsp;${lockedString('is sent to Google')}
@@ -320,42 +321,46 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
320
321
  ></devtools-button>`
321
322
  : Lit.nothing}
322
323
  <div
323
- role=button
324
324
  class=${Lit.Directives.classMap({
325
325
  'resource-link': true,
326
326
  'has-picker-behavior': input.conversationType === AiAssistanceModel.AiHistoryStorage.ConversationType.STYLING,
327
- disabled: input.isTextInputDisabled,
328
327
  })}
329
- tabindex=${(input.conversationType === AiAssistanceModel.AiHistoryStorage.ConversationType.STYLING || input.isTextInputDisabled) ? '-1' : '0'}
330
- @click=${input.onContextClick}
331
- @keydown=${(ev: KeyboardEvent) => {
332
- if (ev.key === 'Enter' || ev.key === ' ') {
333
- void input.onContextClick();
334
- }
335
- }}
336
- aria-description=${i18nString(UIStrings.revealContextDescription)}
337
328
  >
338
- ${input.selectedContext instanceof AiAssistanceModel.NetworkAgent.RequestContext ?
339
- PanelUtils.PanelUtils.getIconForNetworkRequest(input.selectedContext.getItem()) :
340
- input.selectedContext instanceof AiAssistanceModel.FileAgent.FileContext ?
341
- PanelUtils.PanelUtils.getIconForSourceFile(input.selectedContext.getItem()) :
342
- input.selectedContext instanceof AiAssistanceModel.PerformanceAgent.PerformanceTraceContext ?
343
- html`<devtools-icon name="performance" title="Performance"></devtools-icon>` :
344
- Lit.nothing}
345
- <span class="title">
346
- ${input.selectedContext instanceof AiAssistanceModel.StylingAgent.NodeContext ?
329
+ ${
330
+ input.selectedContext instanceof AiAssistanceModel.StylingAgent.NodeContext ?
347
331
  html`
348
- <devtools-widget .widgetConfig=${UI.Widget.widgetConfig(PanelsCommon.DOMLinkifier.DOMNodeLink, {
349
- node: input.selectedContext.getItem(),
350
- options: {
351
- hiddenClassList: input.selectedContext.getItem().classNames().filter(
352
- className => className.startsWith(AiAssistanceModel.Injected.AI_ASSISTANCE_CSS_CLASS_NAME)),
353
- disabled: input.isTextInputDisabled,
354
- },
355
- })}></devtools-widget>`
356
- :
357
- input.selectedContext.getTitle()}
358
- </span>
332
+ <devtools-widget
333
+ class="title"
334
+ .widgetConfig=${UI.Widget.widgetConfig(PanelsCommon.DOMLinkifier.DOMNodeLink, {
335
+ node: input.selectedContext.getItem(),
336
+ options: {
337
+ hiddenClassList: input.selectedContext.getItem().classNames().filter(
338
+ className => className.startsWith(AiAssistanceModel.Injected.AI_ASSISTANCE_CSS_CLASS_NAME)),
339
+ ariaDescription: i18nString(UIStrings.revealContextDescription),
340
+ },
341
+ })}
342
+ ></devtools-widget>` :
343
+ html`
344
+ ${input.selectedContext instanceof AiAssistanceModel.NetworkAgent.RequestContext ?
345
+ PanelUtils.PanelUtils.getIconForNetworkRequest(input.selectedContext.getItem()) :
346
+ input.selectedContext instanceof AiAssistanceModel.FileAgent.FileContext ?
347
+ PanelUtils.PanelUtils.getIconForSourceFile(input.selectedContext.getItem()) :
348
+ input.selectedContext instanceof AiAssistanceModel.PerformanceAgent.PerformanceTraceContext ?
349
+ html`<devtools-icon name="performance" title="Performance"></devtools-icon>` :
350
+ Lit.nothing}
351
+ <span
352
+ role="button"
353
+ class="title"
354
+ tabindex="0"
355
+ @click=${input.onContextClick}
356
+ @keydown=${(ev: KeyboardEvent) => {
357
+ if (ev.key === 'Enter' || ev.key === ' ') {
358
+ void input.onContextClick();
359
+ }
360
+ }}
361
+ aria-description=${i18nString(UIStrings.revealContextDescription)}
362
+ >${input.selectedContext.getTitle()}</span>`
363
+ }
359
364
  ${input.onContextRemoved ? html`
360
365
  <devtools-button
361
366
  title=${getContextRemoveLabel(input.selectedContext)}
@@ -218,9 +218,9 @@
218
218
  gap: var(--sys-size-3);
219
219
  align-items: center;
220
220
 
221
- .resource-link,
222
- .resource-task {
221
+ .resource-link {
223
222
  display: flex;
223
+ background-color: var(--sys-color-cdt-base-container);
224
224
  align-items: center;
225
225
  cursor: pointer;
226
226
  padding: var(--sys-size-2) var(--sys-size-3);
@@ -250,6 +250,10 @@
250
250
 
251
251
  &.has-picker-behavior {
252
252
  overflow: visible;
253
+
254
+ .title {
255
+ overflow: visible;
256
+ }
253
257
  }
254
258
 
255
259
  &:focus-visible {
@@ -301,13 +305,6 @@
301
305
  }
302
306
  }
303
307
  }
304
-
305
- .resource-link.disabled,
306
- .resource-task.disabled {
307
- color: var(--sys-color-state-disabled);
308
- border-color: var(--sys-color-neutral-outline);
309
- pointer-events: none;
310
- }
311
308
  }
312
309
 
313
310
  .link {
@@ -11,7 +11,6 @@ import * as Platform from '../../core/platform/platform.js';
11
11
  import * as SDK from '../../core/sdk/sdk.js';
12
12
  import type * as Protocol from '../../generated/protocol.js';
13
13
  import * as TextUtils from '../../models/text_utils/text_utils.js';
14
- import * as LegacyWrapper from '../../ui/components/legacy_wrapper/legacy_wrapper.js';
15
14
  import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
16
15
  import * as UI from '../../ui/legacy/legacy.js';
17
16
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
@@ -541,10 +540,9 @@ export class RequestView extends UI.Widget.VBox {
541
540
  this.resourceViewTabSetting =
542
541
  Common.Settings.Settings.instance().createSetting('cache-storage-view-tab', 'preview');
543
542
 
544
- this.tabbedPane.appendTab(
545
- 'headers', i18nString(UIStrings.headers),
546
- LegacyWrapper.LegacyWrapper.legacyWrapper(
547
- UI.Widget.VBox, new Network.RequestHeadersView.RequestHeadersView(request)));
543
+ const requestHeadersView = new Network.RequestHeadersView.RequestHeadersView();
544
+ requestHeadersView.request = request;
545
+ this.tabbedPane.appendTab('headers', i18nString(UIStrings.headers), requestHeadersView);
548
546
  this.tabbedPane.appendTab(
549
547
  'preview', i18nString(UIStrings.preview), new Network.RequestPreviewView.RequestPreviewView(request));
550
548
  this.tabbedPane.show(this.element);
@@ -374,6 +374,7 @@ export class PreloadingAttemptView extends UI.Widget.VBox {
374
374
  private readonly preloadingDetails =
375
375
  new PreloadingComponents.PreloadingDetailsReportView.PreloadingDetailsReportView();
376
376
  private readonly ruleSetSelector: PreloadingRuleSetSelector;
377
+ private clearButton: UI.Toolbar.ToolbarButton;
377
378
 
378
379
  constructor(model: SDK.PreloadingModel.PreloadingModel) {
379
380
  super({
@@ -415,6 +416,23 @@ export class PreloadingAttemptView extends UI.Widget.VBox {
415
416
 
416
417
  const toolbar = vbox.contentElement.createChild('devtools-toolbar', 'preloading-toolbar');
417
418
  toolbar.setAttribute('jslog', `${VisualLogging.toolbar()}`);
419
+
420
+ // Clear button first (leftmost)
421
+ this.clearButton =
422
+ new UI.Toolbar.ToolbarButton('Clear speculative loads', 'clear', undefined, 'clear-speculative-loads');
423
+ this.clearButton.addEventListener(UI.Toolbar.ToolbarButton.Events.CLICK, () => {
424
+ const model =
425
+ SDK.TargetManager.TargetManager.instance().scopeTarget()?.model(SDK.PreloadingModel.PreloadingModel);
426
+ if (!model) {
427
+ return;
428
+ }
429
+
430
+ model.reset();
431
+ this.ruleSetSelector.select(null);
432
+ });
433
+ toolbar.appendToolbarItem(this.clearButton);
434
+
435
+ // Rule set dropdown
418
436
  this.ruleSetSelector = new PreloadingRuleSetSelector(() => this.render());
419
437
  toolbar.appendToolbarItem(this.ruleSetSelector.item());
420
438
 
@@ -4,11 +4,19 @@
4
4
  * found in the LICENSE file.
5
5
  */
6
6
 
7
+ :host {
8
+ height: 100%;
9
+ }
10
+
7
11
  .placeholder {
8
12
  display: flex;
9
13
  height: 100%;
10
14
  }
11
15
 
16
+ .ruleset-header-container {
17
+ flex-shrink: 0;
18
+ }
19
+
12
20
  .ruleset-header {
13
21
  padding: 4px 8px;
14
22
  white-space: nowrap;
@@ -20,3 +28,7 @@
20
28
  .ruleset-header devtools-icon {
21
29
  vertical-align: sub;
22
30
  }
31
+
32
+ .text-editor-container {
33
+ overflow: auto;
34
+ }
@@ -49,7 +49,7 @@ export const DEFAULT_VIEW = (input: ViewInput|null, _output: object, target: HTM
49
49
  <style>${UI.inspectorCommonStyles}</style>
50
50
  ${input
51
51
  ? html`
52
- <div class="content">
52
+ <div class="ruleset-header-container">
53
53
  <div class="ruleset-header" id="ruleset-url">${input.url}</div>
54
54
  ${input.errorMessage ? html`
55
55
  <div class="ruleset-header">
@@ -59,8 +59,8 @@ export const DEFAULT_VIEW = (input: ViewInput|null, _output: object, target: HTM
59
59
  </div>
60
60
  ` : nothing}
61
61
  </div>
62
- <div class="text-ellipsis">
63
- <devtools-text-editor .style.flexGrow=${'1'} .state=${input.editorState}></devtools-text-editor>
62
+ <div class="text-editor-container">
63
+ <devtools-text-editor .state=${input.editorState}></devtools-text-editor>
64
64
  </div>`
65
65
  : html`
66
66
  <div class="placeholder">
@@ -150,12 +150,20 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
150
150
  const shouldExpandCategory = (breakpoints: SDK.CategorizedBreakpoint.CategorizedBreakpoint[]): boolean =>
151
151
  Boolean(input.filterText) || (input.highlightedItem && breakpoints.includes(input.highlightedItem)) ||
152
152
  breakpoints.some(breakpoint => breakpoint.enabled());
153
- const filter = (breakpoint: SDK.CategorizedBreakpoint.CategorizedBreakpoint): boolean => !input.filterText ||
154
- Boolean(Sources.CategorizedBreakpointL10n.getLocalizedBreakpointName(breakpoint.name).match(input.filterText)) ||
153
+ const filterRegex =
154
+ input.filterText ? new RegExp(Platform.StringUtilities.escapeForRegExp(input.filterText), 'i') : null;
155
+ const filter = (breakpoint: SDK.CategorizedBreakpoint.CategorizedBreakpoint): boolean => !filterRegex ||
156
+ Boolean(Sources.CategorizedBreakpointL10n.getLocalizedBreakpointName(breakpoint.name).match(filterRegex)) ||
155
157
  breakpoint === input.highlightedItem;
156
158
  const filteredCategories =
157
159
  input.sortedCategoryNames.values()
158
- .map(category => [category, input.categories.get(category)?.filter(filter)])
160
+ .map(category => {
161
+ const breakpoints = input.categories.get(category);
162
+ if (filterRegex && getLocalizedCategory(category).match(filterRegex)) {
163
+ return [category, breakpoints];
164
+ }
165
+ return [category, breakpoints?.filter(filter)];
166
+ })
159
167
  .filter(
160
168
  (filteredCategory): filteredCategory is
161
169
  [SDK.CategorizedBreakpoint.Category, SDK.CategorizedBreakpoint.CategorizedBreakpoint[]] =>
@@ -12,7 +12,7 @@ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
12
12
 
13
13
  import domLinkifierStyles from './domLinkifier.css.js';
14
14
 
15
- const {classMap} = Directives;
15
+ const {classMap, ifDefined} = Directives;
16
16
 
17
17
  const UIStrings = {
18
18
  /**
@@ -33,6 +33,7 @@ export interface Options {
33
33
  isDynamicLink?: boolean;
34
34
  hiddenClassList?: string[];
35
35
  disabled?: boolean;
36
+ ariaDescription?: string;
36
37
  }
37
38
 
38
39
  interface ViewInput {
@@ -43,6 +44,7 @@ interface ViewInput {
43
44
  id?: string;
44
45
  classes: string[];
45
46
  pseudo?: string;
47
+ ariaDescription?: string;
46
48
  onClick: () => void;
47
49
  onMouseOver: () => void;
48
50
  onMouseLeave: () => void;
@@ -59,6 +61,7 @@ const DEFAULT_VIEW: View = (input, _output, target: HTMLElement) => {
59
61
  'dynamic-link': Boolean(input.dynamic),
60
62
  disabled: Boolean(input.disabled)
61
63
  })}"
64
+ aria-description=${ifDefined(input.ariaDescription)}
62
65
  jslog=${VisualLogging.link('node').track({click: true, keydown: 'Enter'})}
63
66
  tabindex=${input.preventKeyboardFocus ? -1 : 0}
64
67
  @click=${input.onClick}
@@ -112,6 +115,7 @@ export class DOMNodeLink extends UI.Widget.Widget {
112
115
  textContent: undefined,
113
116
  isDynamicLink: false,
114
117
  disabled: false,
118
+ ariaDescription: undefined,
115
119
  };
116
120
  const viewInput: ViewInput = {
117
121
  dynamic: options.isDynamicLink,
@@ -129,6 +133,7 @@ export class DOMNodeLink extends UI.Widget.Widget {
129
133
  onMouseLeave: () => {
130
134
  SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight();
131
135
  },
136
+ ariaDescription: options.ariaDescription,
132
137
  };
133
138
  if (!this.#node) {
134
139
  this.#view(viewInput, {}, this.contentElement);
@@ -252,9 +252,9 @@ export const concatErrorDescriptionAndIssueSummary = (description: string, issue
252
252
  return description;
253
253
  };
254
254
 
255
- // This value reflects the 18px min-height of .console-message, plus the
256
- // 1px border of .console-message-wrapper. Keep in sync with consoleView.css.
257
- const defaultConsoleRowHeight = 19;
255
+ // This value reflects the 18px min-height of .console-message.
256
+ // Keep in sync with consoleView.css.
257
+ const defaultConsoleRowHeight = 18;
258
258
 
259
259
  const parameterToRemoteObject = (runtimeModel: SDK.RuntimeModel.RuntimeModel|null):
260
260
  (parameter?: SDK.RemoteObject.RemoteObject|Protocol.Runtime.RemoteObject|string) => SDK.RemoteObject.RemoteObject =>
@@ -277,7 +277,7 @@ export class ColorSwatchPopoverIcon extends Common.ObjectWrapper.ObjectWrapper<C
277
277
  return;
278
278
  }
279
279
 
280
- this.swatch.color = color;
280
+ this.swatch.renderColor(color);
281
281
  this.dispatchEventToListeners(ColorSwatchPopoverIconEvents.COLOR_CHANGED, color);
282
282
  }
283
283
 
@@ -48,7 +48,6 @@ import * as Lit from '../../ui/lit/lit.js';
48
48
  import * as ElementsComponents from './components/components.js';
49
49
  import computedStyleWidgetStyles from './computedStyleWidget.css.js';
50
50
  import {ImagePreviewPopover} from './ImagePreviewPopover.js';
51
- import {PlatformFontsWidget} from './PlatformFontsWidget.js';
52
51
  import {categorizePropertyName, type Category, DefaultCategoryOrder} from './PropertyNameCategories.js';
53
52
  import {Renderer, rendererBase, type RenderingContext, StringRenderer, URLRenderer} from './PropertyRenderer.js';
54
53
  import {StylePropertiesSection} from './StylePropertiesSection.js';
@@ -208,8 +207,8 @@ class ColorRenderer extends rendererBase(SDK.CSSPropertyParserMatchers.ColorMatc
208
207
  }
209
208
 
210
209
  const swatch = new InlineEditor.ColorSwatch.ColorSwatch();
211
- swatch.readonly = true;
212
- swatch.color = color;
210
+ swatch.setReadonly(true);
211
+ swatch.renderColor(color);
213
212
  const valueElement = document.createElement('span');
214
213
  valueElement.textContent = match.text;
215
214
 
@@ -265,11 +264,11 @@ type ComputedStyleData = {
265
264
  interface ComputedStyleWidgetInput {
266
265
  computedStylesTree: TreeOutline.TreeOutline.TreeOutline<ComputedStyleData>;
267
266
  hasMatches: boolean;
268
- computedStyleModel?: ComputedStyleModule.ComputedStyleModel.ComputedStyleModel;
269
267
  showInheritedComputedStylePropertiesSetting: Common.Settings.Setting<boolean>;
270
268
  groupComputedStylesSetting: Common.Settings.Setting<boolean>;
271
269
  onFilterChanged: (event: CustomEvent<string>) => void;
272
270
  filterText: string;
271
+ onRegexToggled: () => void;
273
272
  }
274
273
 
275
274
  type View = (input: ComputedStyleWidgetInput, output: null, target: HTMLElement) => void;
@@ -283,8 +282,10 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
283
282
  <devtools-toolbar-input
284
283
  type="filter"
285
284
  autofocus
285
+ ?regex=${true}
286
286
  value=${input.filterText}
287
287
  @change=${input.onFilterChanged}
288
+ @regextoggle=${input.onRegexToggled}
288
289
  ></devtools-toolbar-input>
289
290
  <devtools-checkbox
290
291
  title=${i18nString(UIStrings.showAll)}
@@ -298,7 +299,6 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
298
299
  </div>
299
300
  ${input.computedStylesTree}
300
301
  ${!input.hasMatches ? html`<div class="gray-info-message">${i18nString(UIStrings.noMatchingProperty)}</div>` : ''}
301
- ${input.computedStyleModel ? html`<devtools-widget .widgetConfig=${UI.Widget.widgetConfig(PlatformFontsWidget, { sharedModel: input.computedStyleModel})}></devtools-widget>` : ''}
302
302
  `, target);
303
303
  // clang-format on
304
304
  };
@@ -317,6 +317,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
317
317
  #treeData?: TreeOutline.TreeOutline.TreeOutlineData<ComputedStyleData>;
318
318
  readonly #view: View;
319
319
  #filterText = '';
320
+ #isRegex = false;
320
321
 
321
322
  constructor() {
322
323
  super({useShadowDom: true});
@@ -351,16 +352,6 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
351
352
  this.#computedStylesTree.classList.toggle('computed-narrow', isNarrow);
352
353
  }
353
354
 
354
- override wasShown(): void {
355
- UI.Context.Context.instance().setFlavor(ComputedStyleWidget, this);
356
- super.wasShown();
357
- }
358
-
359
- override willHide(): void {
360
- super.willHide();
361
- UI.Context.Context.instance().setFlavor(ComputedStyleWidget, null);
362
- }
363
-
364
355
  /**
365
356
  * @param input.hasMatches Whether any properties matched the current filter (or if any properties exist at all).
366
357
  */
@@ -369,11 +360,11 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
369
360
  {
370
361
  computedStylesTree: this.#computedStylesTree,
371
362
  hasMatches,
372
- computedStyleModel: this.#computedStyleModel,
373
363
  showInheritedComputedStylePropertiesSetting: this.showInheritedComputedStylePropertiesSetting,
374
364
  groupComputedStylesSetting: this.groupComputedStylesSetting,
375
365
  onFilterChanged: this.onFilterChanged.bind(this),
376
366
  filterText: this.#filterText,
367
+ onRegexToggled: this.onRegexToggled.bind(this),
377
368
  },
378
369
  null, this.contentElement);
379
370
  }
@@ -654,10 +645,28 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
654
645
  return result;
655
646
  }
656
647
 
648
+ #buildFilterRegex(text: string): RegExp|null {
649
+ if (!text) {
650
+ return null;
651
+ }
652
+ if (this.#isRegex) {
653
+ try {
654
+ return new RegExp(text, 'i');
655
+ } catch {
656
+ // Invalid regex: fall through to plain-text matching.
657
+ }
658
+ }
659
+ return new RegExp(Platform.StringUtilities.escapeForRegExp(text), 'i');
660
+ }
661
+
662
+ private async onRegexToggled(): Promise<void> {
663
+ this.#isRegex = !this.#isRegex;
664
+ await this.filterComputedStyles(this.#buildFilterRegex(this.#filterText));
665
+ }
666
+
657
667
  private async onFilterChanged(event: CustomEvent<string>): Promise<void> {
658
668
  this.#filterText = event.detail;
659
- await this.filterComputedStyles(
660
- event.detail ? new RegExp(Platform.StringUtilities.escapeForRegExp(event.detail), 'i') : null);
669
+ await this.filterComputedStyles(this.#buildFilterRegex(event.detail));
661
670
 
662
671
  if (event.detail && this.#computedStylesTree.data && this.#computedStylesTree.data.tree) {
663
672
  UI.ARIAUtils.LiveAnnouncer.alert(i18nString(
@@ -59,6 +59,7 @@ import {DOMTreeWidget, type ElementsTreeOutline} from './ElementsTreeOutline.js'
59
59
  import {LayoutPane} from './LayoutPane.js';
60
60
  import type {MarkerDecorator} from './MarkerDecorator.js';
61
61
  import {MetricsSidebarPane} from './MetricsSidebarPane.js';
62
+ import {PlatformFontsWidget} from './PlatformFontsWidget.js';
62
63
  import {
63
64
  Events as StylesSidebarPaneEvents,
64
65
  StylesSidebarPane,
@@ -312,8 +313,6 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
312
313
 
313
314
  UI.Context.Context.instance().addFlavorChangeListener(
314
315
  StylesSidebarPane, this.evaluateTrackingComputedStyleUpdatesForNode, this);
315
- UI.Context.Context.instance().addFlavorChangeListener(
316
- ComputedStyleWidget, this.evaluateTrackingComputedStyleUpdatesForNode, this);
317
316
 
318
317
  this.stylesWidget = new StylesSidebarPane(this.#computedStyleModel);
319
318
  this.#computedStyleWidget = new ComputedStyleWidget();
@@ -372,7 +371,7 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
372
371
  return;
373
372
  }
374
373
 
375
- const isComputedStyleWidgetVisible = Boolean(UI.Context.Context.instance().flavor(ComputedStyleWidget));
374
+ const isComputedStyleWidgetVisible = this.#computedStyleWidget.isShowing();
376
375
  const isStylesTabVisible = Boolean(UI.Context.Context.instance().flavor(StylesSidebarPane));
377
376
  const shouldTrackComputedStyleUpdates = isComputedStyleWidgetVisible ||
378
377
  (isStylesTabVisible && Root.Runtime.hostConfig.devToolsAnimationStylesInStylesTab?.enabled);
@@ -550,6 +549,7 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
550
549
  super.wasShown();
551
550
  UI.Context.Context.instance().setFlavor(ElementsPanel, this);
552
551
  this.#domTreeWidget.show(this.domTreeContainer);
552
+ this.evaluateTrackingComputedStyleUpdatesForNode();
553
553
 
554
554
  if (Annotations.AnnotationRepository.annotationsEnabled()) {
555
555
  void PanelCommon.AnnotationManager.instance().resolveAnnotationsOfType(Annotations.AnnotationType.ELEMENT_NODE);
@@ -558,6 +558,7 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
558
558
 
559
559
  override willHide(): void {
560
560
  SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight();
561
+ this.evaluateTrackingComputedStyleUpdatesForNode();
561
562
  this.#domTreeWidget.detach();
562
563
  super.willHide();
563
564
  UI.Context.Context.instance().setFlavor(ElementsPanel, null);
@@ -1116,10 +1117,16 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
1116
1117
  this.setupTextSelectionHack(matchedStylePanesWrapper.element);
1117
1118
 
1118
1119
  const computedStylePanesWrapper = new UI.Widget.VBox();
1119
- computedStylePanesWrapper.element.classList.add('style-panes-wrapper');
1120
+ computedStylePanesWrapper.element.classList.add('style-panes-wrapper', 'computed-styles-pane-wrapper');
1120
1121
  computedStylePanesWrapper.element.setAttribute('jslog', `${VisualLogging.pane('computed').track({resize: true})}`);
1122
+ this.#computedStyleWidget.element.classList.add('computed-styles-wrapper');
1121
1123
  this.#computedStyleWidget.show(computedStylePanesWrapper.element);
1122
1124
 
1125
+ const platformFontsWidget = new PlatformFontsWidget();
1126
+ platformFontsWidget.element.classList.add('platform-fonts-wrapper');
1127
+ platformFontsWidget.sharedModel = this.#computedStyleModel;
1128
+ platformFontsWidget.show(computedStylePanesWrapper.element);
1129
+
1123
1130
  const stylesSplitWidget = new UI.SplitWidget.SplitWidget(
1124
1131
  true /* isVertical */, true /* secondIsSidebar */, 'elements.styles.sidebar.width', 100);
1125
1132
  stylesSplitWidget.setMainWidget(matchedStylePanesWrapper);
@@ -1162,6 +1169,7 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
1162
1169
 
1163
1170
  const tabSelected = (event: Common.EventTarget.EventTargetEvent<UI.TabbedPane.EventData>): void => {
1164
1171
  const {tabId} = event.data;
1172
+ this.evaluateTrackingComputedStyleUpdatesForNode();
1165
1173
  if (tabId === SidebarPaneTabId.COMPUTED) {
1166
1174
  computedStylePanesWrapper.show(computedView.element);
1167
1175
  showMetricsWidgetInComputedPane();