chrome-devtools-frontend 1.0.1593959 → 1.0.1595090

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 (73) hide show
  1. package/docs/contributing/settings-experiments-features.md +25 -5
  2. package/front_end/core/common/README.md +126 -0
  3. package/front_end/core/sdk/CSSModel.ts +22 -0
  4. package/front_end/core/sdk/CSSNavigation.ts +33 -0
  5. package/front_end/core/sdk/CSSRule.ts +12 -2
  6. package/front_end/core/sdk/sdk-meta.ts +22 -18
  7. package/front_end/core/sdk/sdk.ts +2 -0
  8. package/front_end/design_system_tokens.css +538 -259
  9. package/front_end/entrypoints/main/main-meta.ts +2 -2
  10. package/front_end/generated/SupportedCSSProperties.js +12 -0
  11. package/front_end/models/issues_manager/Issue.ts +1 -0
  12. package/front_end/models/issues_manager/IssueAggregator.ts +9 -0
  13. package/front_end/models/issues_manager/IssuesManager.ts +5 -0
  14. package/front_end/models/issues_manager/SelectivePermissionsInterventionIssue.ts +65 -0
  15. package/front_end/models/issues_manager/descriptions/selectivePermissionsIntervention.md +7 -0
  16. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  17. package/front_end/models/javascript_metadata/NativeFunctions.js +44 -9
  18. package/front_end/models/persistence/persistence-meta.ts +4 -4
  19. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +12 -1
  20. package/front_end/panels/ai_assistance/components/ChatInput.ts +37 -30
  21. package/front_end/panels/ai_assistance/components/ChatView.ts +4 -2
  22. package/front_end/panels/ai_assistance/components/chatInput.css +26 -1
  23. package/front_end/panels/application/StorageView.ts +8 -2
  24. package/front_end/panels/application/preloading/PreloadingView.ts +105 -7
  25. package/front_end/panels/application/preloading/preloadingView.css +4 -0
  26. package/front_end/panels/console/ConsoleView.ts +2 -2
  27. package/front_end/panels/console/console-meta.ts +18 -14
  28. package/front_end/panels/elements/ComputedStyleWidget.ts +12 -7
  29. package/front_end/panels/elements/ElementsPanel.ts +1 -1
  30. package/front_end/panels/elements/ElementsTreeOutline.ts +4 -6
  31. package/front_end/panels/elements/ImagePreviewPopover.ts +6 -9
  32. package/front_end/panels/elements/StylePropertiesSection.ts +30 -0
  33. package/front_end/panels/elements/StylesSidebarPane.ts +13 -7
  34. package/front_end/panels/elements/elements-meta.ts +12 -8
  35. package/front_end/panels/issues/AffectedSelectivePermissionsInterventionView.ts +120 -0
  36. package/front_end/panels/issues/IssueView.ts +2 -0
  37. package/front_end/panels/issues/IssuesPane.ts +6 -0
  38. package/front_end/panels/issues/issues.ts +2 -0
  39. package/front_end/panels/lighthouse/LighthouseStartView.ts +99 -38
  40. package/front_end/panels/lighthouse/LighthouseTimespanView.ts +53 -14
  41. package/front_end/panels/lighthouse/RadioSetting.ts +33 -19
  42. package/front_end/panels/lighthouse/lighthouse.ts +2 -0
  43. package/front_end/panels/media/PlayerMessagesView.ts +62 -49
  44. package/front_end/panels/media/media.ts +2 -0
  45. package/front_end/panels/media/playerMessagesView.css +1 -1
  46. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +49 -24
  47. package/front_end/panels/settings/FrameworkIgnoreListSettingsTab.ts +2 -2
  48. package/front_end/panels/sources/sources-meta.ts +8 -4
  49. package/front_end/panels/utils/utils.ts +11 -5
  50. package/front_end/third_party/chromium/README.chromium +1 -1
  51. package/front_end/third_party/lit/lib/async-directive.d.ts +465 -0
  52. package/front_end/third_party/lit/lib/async-directive.js +23 -0
  53. package/front_end/third_party/lit/lib/async-directive.js.map +1 -0
  54. package/front_end/third_party/lit/lib/decorators.d.ts +7 -1
  55. package/front_end/third_party/lit/lib/decorators.js +2 -2
  56. package/front_end/third_party/lit/lib/decorators.js.map +1 -1
  57. package/front_end/third_party/lit/lib/directive.js.map +1 -1
  58. package/front_end/third_party/lit/lib/directives.d.ts +27 -8
  59. package/front_end/third_party/lit/lib/directives.js +8 -8
  60. package/front_end/third_party/lit/lib/directives.js.map +1 -1
  61. package/front_end/third_party/lit/lib/lit.d.ts +15 -5
  62. package/front_end/third_party/lit/lib/lit.js +4 -4
  63. package/front_end/third_party/lit/lib/lit.js.map +1 -1
  64. package/front_end/third_party/lit/lib/static-html.js +2 -2
  65. package/front_end/third_party/lit/lib/static-html.js.map +1 -1
  66. package/front_end/third_party/lit/lit.ts +2 -1
  67. package/front_end/third_party/lit/rollup.config.mjs +1 -1
  68. package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +5 -0
  69. package/front_end/ui/legacy/components/utils/ImagePreview.ts +27 -23
  70. package/front_end/ui/lit/lit.ts +1 -0
  71. package/front_end/ui/visual_logging/Debugging.ts +1 -1
  72. package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
  73. package/package.json +1 -1
@@ -13,6 +13,7 @@ import * as Platform from '../../../core/platform/platform.js';
13
13
  import {assertNotNullOrUndefined} from '../../../core/platform/platform.js';
14
14
  import * as SDK from '../../../core/sdk/sdk.js';
15
15
  import * as Protocol from '../../../generated/protocol.js';
16
+ import * as TextUtils from '../../../models/text_utils/text_utils.js';
16
17
  import * as Buttons from '../../../ui/components/buttons/buttons.js';
17
18
  // eslint-disable-next-line @devtools/es-modules-import
18
19
  import emptyWidgetStyles from '../../../ui/legacy/emptyWidget.css.js';
@@ -21,7 +22,7 @@ import {Directives, html, render} from '../../../ui/lit/lit.js';
21
22
  import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
22
23
 
23
24
  import * as PreloadingComponents from './components/components.js';
24
- import {ruleSetTagOrLocationShort} from './components/PreloadingString.js';
25
+ import {capitalizedAction, ruleSetTagOrLocationShort} from './components/PreloadingString.js';
25
26
  import * as PreloadingHelper from './helper/helper.js';
26
27
  import preloadingViewStyles from './preloadingView.css.js';
27
28
  import preloadingViewDropDownStyles from './preloadingViewDropDown.css.js';
@@ -362,6 +363,78 @@ export class PreloadingRuleSetView extends UI.Widget.VBox {
362
363
  }
363
364
  }
364
365
 
366
+ /**
367
+ * Pure filtering function for preloading grid rows.
368
+ * Exported for testability.
369
+ */
370
+ export function applyFilterText(filterText: string, rows: PreloadingComponents.PreloadingGrid.PreloadingGridRow[]):
371
+ PreloadingComponents.PreloadingGrid.PreloadingGridRow[] {
372
+ const trimmedFilter = filterText.trim();
373
+ if (trimmedFilter === '') {
374
+ return rows;
375
+ }
376
+
377
+ const FILTER_KEYS = ['url', 'action', 'status'] as const;
378
+ const parser = new TextUtils.TextUtils.FilterParser([...FILTER_KEYS]);
379
+ // The match is case-insensitive. We handle the matching with everything lower cased,
380
+ // both keywords and values.
381
+ const query = parser.parse(filterText.toLowerCase());
382
+
383
+ // Drop the last term if it is an incomplete filter key (e.g., "action:" with no value).
384
+ // FilterParser parses "action:" as plain text since KEY_VALUE_FILTER_REGEXP requires a value.
385
+ // This lets users type "url:foo action:" and still see results for "url:foo".
386
+ const lastTerm = query.at(-1);
387
+
388
+ // If the parse result is empty, the query only contains spaces.
389
+ if (!lastTerm) {
390
+ return rows;
391
+ }
392
+
393
+ const isKeyWithNoValue =
394
+ (lastTerm.key === undefined || lastTerm.key === null) && FILTER_KEYS.some(key => lastTerm.text === `${key}:`);
395
+ if (isKeyWithNoValue) {
396
+ query.pop();
397
+ }
398
+
399
+ if (query.length === 0) {
400
+ return rows;
401
+ }
402
+
403
+ return rows.filter(row => {
404
+ const attempt = row.pipeline.getOriginallyTriggered();
405
+ const url = attempt.key.url.toLowerCase();
406
+ const action = capitalizedAction(attempt.action).toLowerCase();
407
+ const status = PreloadingUIUtils.status(attempt.status).toLowerCase();
408
+
409
+ // Each term must match (AND logic between terms)
410
+ return query.every(term => {
411
+ if (term.text === undefined || term.text === null || term.text === '') {
412
+ return true;
413
+ }
414
+ const searchText = term.text.toLowerCase();
415
+
416
+ // The query is lowercased before parsing, so keys are already normalized.
417
+ const key = term.key;
418
+ switch (key) {
419
+ case 'url':
420
+ return url.includes(searchText);
421
+ case 'action':
422
+ return action.includes(searchText);
423
+ case 'status': {
424
+ // Support multiple status values separated by comma (e.g., "status:ready,success")
425
+ const statusValues = searchText.split(',');
426
+ return statusValues.some(v => status.includes(v));
427
+ }
428
+ case undefined:
429
+ // No key specified: search across all columns (URL, action, status)
430
+ return url.includes(searchText) || action.includes(searchText) || status.includes(searchText);
431
+ default:
432
+ return false;
433
+ }
434
+ });
435
+ });
436
+ }
437
+
365
438
  export class PreloadingAttemptView extends UI.Widget.VBox {
366
439
  private model: SDK.PreloadingModel.PreloadingModel;
367
440
  // Note that we use id of (representative) preloading attempt while we show pipelines in grid.
@@ -374,6 +447,7 @@ export class PreloadingAttemptView extends UI.Widget.VBox {
374
447
  private readonly preloadingDetails =
375
448
  new PreloadingComponents.PreloadingDetailsReportView.PreloadingDetailsReportView();
376
449
  private readonly ruleSetSelector: PreloadingRuleSetSelector;
450
+ private readonly textFilterUI: UI.Toolbar.ToolbarFilter;
377
451
  private clearButton: UI.Toolbar.ToolbarButton;
378
452
 
379
453
  constructor(model: SDK.PreloadingModel.PreloadingModel) {
@@ -417,7 +491,19 @@ export class PreloadingAttemptView extends UI.Widget.VBox {
417
491
  const toolbar = vbox.contentElement.createChild('devtools-toolbar', 'preloading-toolbar');
418
492
  toolbar.setAttribute('jslog', `${VisualLogging.toolbar()}`);
419
493
 
420
- // Clear button first (leftmost)
494
+ // Rule set dropdown first
495
+ this.ruleSetSelector = new PreloadingRuleSetSelector(() => this.render());
496
+ toolbar.appendToolbarItem(this.ruleSetSelector.item());
497
+
498
+ // Text filter second
499
+ this.textFilterUI = new UI.Toolbar.ToolbarFilter(undefined, 1, 1);
500
+ this.textFilterUI.addEventListener(UI.Toolbar.ToolbarInput.Event.TEXT_CHANGED, this.onTextFilterChanged, this);
501
+ toolbar.appendToolbarItem(this.textFilterUI);
502
+
503
+ // Separator between text filter and clear button
504
+ toolbar.appendToolbarItem(new UI.Toolbar.ToolbarSeparator());
505
+
506
+ // Clear button last (rightmost)
421
507
  this.clearButton =
422
508
  new UI.Toolbar.ToolbarButton('Clear speculative loads', 'clear', undefined, 'clear-speculative-loads');
423
509
  this.clearButton.addEventListener(UI.Toolbar.ToolbarButton.Events.CLICK, () => {
@@ -428,14 +514,13 @@ export class PreloadingAttemptView extends UI.Widget.VBox {
428
514
  }
429
515
 
430
516
  model.reset();
517
+ // Reset UI state
518
+ this.textFilterUI.setValue('');
431
519
  this.ruleSetSelector.select(null);
520
+ this.render();
432
521
  });
433
522
  toolbar.appendToolbarItem(this.clearButton);
434
523
 
435
- // Rule set dropdown
436
- this.ruleSetSelector = new PreloadingRuleSetSelector(() => this.render());
437
- toolbar.appendToolbarItem(this.ruleSetSelector.item());
438
-
439
524
  this.preloadingGrid.onSelect = this.onPreloadingGridCellFocused.bind(this);
440
525
 
441
526
  const preloadingGridContainer = document.createElement('div');
@@ -491,6 +576,14 @@ export class PreloadingAttemptView extends UI.Widget.VBox {
491
576
  }
492
577
 
493
578
  this.ruleSetSelector.select(id);
579
+
580
+ // Reset text filter when navigating from Rules view to clear any existing filter
581
+ this.textFilterUI.setValue('');
582
+ this.render();
583
+ }
584
+
585
+ private onTextFilterChanged(): void {
586
+ this.render();
494
587
  }
495
588
 
496
589
  private updatePreloadingDetails(): void {
@@ -532,8 +625,13 @@ export class PreloadingAttemptView extends UI.Widget.VBox {
532
625
  statusCode,
533
626
  };
534
627
  });
535
- this.preloadingGrid.rows = rows;
628
+
629
+ // Apply text filter
630
+ const filteredRows = applyFilterText(this.textFilterUI.valueWithoutSuggestion(), rows);
631
+
632
+ this.preloadingGrid.rows = filteredRows;
536
633
  this.preloadingGrid.pageURL = pageURL();
634
+ // Only show empty state when there are truly no speculations (not when filter has no matches)
537
635
  this.contentElement.classList.toggle('empty', rows.length === 0);
538
636
 
539
637
  this.updatePreloadingDetails();
@@ -25,6 +25,10 @@
25
25
  button.toolbar-has-dropdown {
26
26
  margin: var(--sys-size-2) 0;
27
27
  }
28
+
29
+ .toolbar-filter {
30
+ max-width: var(--sys-size-29);
31
+ }
28
32
  }
29
33
 
30
34
  devtools-split-view {
@@ -107,11 +107,11 @@ const UIStrings = {
107
107
  /**
108
108
  * @description Title of a setting under the Console category that can be invoked through the Command Menu
109
109
  */
110
- groupSimilarMessagesInConsole: 'Group similar messages in console',
110
+ groupSimilarMessagesInConsole: 'Group similar messages',
111
111
  /**
112
112
  * @description Title of a setting under the Console category that can be invoked through the Command Menu
113
113
  */
114
- showCorsErrorsInConsole: 'Show `CORS` errors in console',
114
+ showCorsErrorsInConsole: 'CORS errors in console',
115
115
  /**
116
116
  * @description Tooltip for the the console sidebar toggle in the Console panel. Command to
117
117
  * open/show the sidebar.
@@ -62,11 +62,11 @@ const UIStrings = {
62
62
  */
63
63
  timestamps: 'Timestamps',
64
64
  /**
65
- * @description Title of a setting under the Console category that can be invoked through the Command Menu
65
+ * @description Title of an option under the Console category that can be invoked through the Command Menu
66
66
  */
67
67
  showTimestamps: 'Show timestamps',
68
68
  /**
69
- * @description Title of a setting under the Console category that can be invoked through the Command Menu
69
+ * @description Title of an option under the Console category that can be invoked through the Command Menu
70
70
  */
71
71
  hideTimestamps: 'Hide timestamps',
72
72
  /**
@@ -88,19 +88,23 @@ const UIStrings = {
88
88
  /**
89
89
  * @description Title of a setting under the Console category that can be invoked through the Command Menu
90
90
  */
91
- groupSimilarMessagesInConsole: 'Group similar messages in console',
91
+ groupSimilarMessages: 'Group similar messages',
92
92
  /**
93
93
  * @description Title of a setting under the Console category that can be invoked through the Command Menu
94
94
  */
95
- doNotGroupSimilarMessagesIn: 'Do not group similar messages in console',
95
+ doNotGroupSimilarMessages: 'Don\'t group similar messages',
96
96
  /**
97
- * @description Title of a setting under the Console category that can be invoked through the Command Menu
97
+ * @description Title of a setting under the Console category in Settings
98
98
  */
99
- showCorsErrorsInConsole: 'Show `CORS` errors in console',
99
+ corsErrorsInConsole: 'CORS errors in console',
100
100
  /**
101
- * @description Title of a setting under the Console category that can be invoked through the Command Menu
101
+ * @description Title of an option under the Console category that can be invoked through the Command Menu
102
+ */
103
+ showCorsErrorsInConsole: 'Show CORS errors in console',
104
+ /**
105
+ * @description Title of an option under the Console category that can be invoked through the Command Menu
102
106
  */
103
- doNotShowCorsErrorsIn: 'Do not show `CORS` errors in console',
107
+ doNotShowCorsErrorsIn: 'Don\'t show CORS errors in console',
104
108
  /**
105
109
  * @description Title of a setting under the Console category in Settings
106
110
  */
@@ -137,7 +141,7 @@ const UIStrings = {
137
141
  * @description Title of a setting under the Console category in Settings that controls whether AI summaries should
138
142
  * be shown for console warnings/errors.
139
143
  */
140
- showConsoleInsightTeasers: 'Show AI summaries for console messages',
144
+ consoleInsightTeasers: 'AI summaries for console messages',
141
145
  } as const;
142
146
  const str_ = i18n.i18n.registerUIStrings('panels/console/console-meta.ts', UIStrings);
143
147
  const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
@@ -342,25 +346,25 @@ Common.Settings.registerSettingExtension({
342
346
  Common.Settings.registerSettingExtension({
343
347
  category: Common.Settings.SettingCategory.CONSOLE,
344
348
  storageType: Common.Settings.SettingStorageType.SYNCED,
345
- title: i18nLazyString(UIStrings.groupSimilarMessagesInConsole),
349
+ title: i18nLazyString(UIStrings.groupSimilarMessages),
346
350
  settingName: 'console-group-similar',
347
351
  settingType: Common.Settings.SettingType.BOOLEAN,
348
352
  defaultValue: true,
349
353
  options: [
350
354
  {
351
355
  value: true,
352
- title: i18nLazyString(UIStrings.groupSimilarMessagesInConsole),
356
+ title: i18nLazyString(UIStrings.groupSimilarMessages),
353
357
  },
354
358
  {
355
359
  value: false,
356
- title: i18nLazyString(UIStrings.doNotGroupSimilarMessagesIn),
360
+ title: i18nLazyString(UIStrings.doNotGroupSimilarMessages),
357
361
  },
358
362
  ],
359
363
  });
360
364
 
361
365
  Common.Settings.registerSettingExtension({
362
366
  category: Common.Settings.SettingCategory.CONSOLE,
363
- title: i18nLazyString(UIStrings.showCorsErrorsInConsole),
367
+ title: i18nLazyString(UIStrings.corsErrorsInConsole),
364
368
  settingName: 'console-shows-cors-errors',
365
369
  settingType: Common.Settings.SettingType.BOOLEAN,
366
370
  defaultValue: true,
@@ -436,7 +440,7 @@ Common.Settings.registerSettingExtension({
436
440
  Common.Settings.registerSettingExtension({
437
441
  category: Common.Settings.SettingCategory.CONSOLE,
438
442
  storageType: Common.Settings.SettingStorageType.SYNCED,
439
- title: i18nLazyString(UIStrings.showConsoleInsightTeasers),
443
+ title: i18nLazyString(UIStrings.consoleInsightTeasers),
440
444
  settingName: 'console-insight-teasers-enabled',
441
445
  settingType: Common.Settings.SettingType.BOOLEAN,
442
446
  defaultValue: true,
@@ -353,13 +353,18 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
353
353
 
354
354
  this.filterRegex = null;
355
355
  this.linkifier = new Components.Linkifier.Linkifier(maxLinkLength);
356
- this.imagePreviewPopover = new ImagePreviewPopover(this.contentElement, event => {
357
- const link = event.composedPath()[0];
358
- if (link instanceof Element) {
359
- return link;
360
- }
361
- return null;
362
- }, () => this.#computedStyleModel ? this.#computedStyleModel.node : null);
356
+ this.imagePreviewPopover = new ImagePreviewPopover(
357
+ this.contentElement,
358
+ event => {
359
+ const link = event.composedPath()[0];
360
+ if (link instanceof Element) {
361
+ return link;
362
+ }
363
+ return null;
364
+ },
365
+ async () => {
366
+ return await Components.ImagePreview.loadPrecomputedFeatures(this.#computedStyleModel?.node);
367
+ });
363
368
 
364
369
  this.#updateView({hasMatches: true});
365
370
  }
@@ -1556,7 +1556,7 @@ export class DOMNodeRevealer implements
1556
1556
  }
1557
1557
 
1558
1558
  if (resolvedNode) {
1559
- const opts: RevealAndSelectNodeOpts = {showPanel: true, focusNode: !omitFocus};
1559
+ const opts: RevealAndSelectNodeOpts = omitFocus ? {showPanel: false} : {showPanel: true, focusNode: true};
1560
1560
  const promise = resolvedNode instanceof SDK.DOMModel.AdoptedStyleSheet ?
1561
1561
  panel.revealAndSelectAdoptedStyleSheet(resolvedNode, opts) :
1562
1562
  panel.revealAndSelectNode(resolvedNode, opts);
@@ -43,6 +43,7 @@ import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
43
43
  import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
44
44
  import * as Highlighting from '../../ui/components/highlighting/highlighting.js';
45
45
  import * as IssueCounter from '../../ui/components/issue_counter/issue_counter.js';
46
+ import * as UIComponentUtils from '../../ui/legacy/components/utils/utils.js';
46
47
  import * as UI from '../../ui/legacy/legacy.js';
47
48
  import {html, nothing, render} from '../../ui/lit/lit.js';
48
49
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
@@ -555,18 +556,15 @@ export class ElementsTreeOutline extends
555
556
  }
556
557
  return link;
557
558
  },
558
- link => {
559
+ async link => {
559
560
  const listItem = UI.UIUtils.enclosingNodeOrSelfWithNodeName(link, 'li');
560
561
  if (!listItem) {
561
- return null;
562
+ return undefined;
562
563
  }
563
564
 
564
565
  const treeElement =
565
566
  (UI.TreeOutline.TreeElement.getTreeElementBylistItemNode(listItem) as ElementsTreeElement | undefined);
566
- if (!treeElement) {
567
- return null;
568
- }
569
- return treeElement.node();
567
+ return await UIComponentUtils.ImagePreview.loadPrecomputedFeatures(treeElement?.node());
570
568
  });
571
569
 
572
570
  this.updateRecords = new Map();
@@ -3,7 +3,6 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import type * as Platform from '../../core/platform/platform.js';
6
- import type * as SDK from '../../core/sdk/sdk.js';
7
6
  import * as Components from '../../ui/legacy/components/utils/utils.js';
8
7
  import * as UI from '../../ui/legacy/legacy.js';
9
8
 
@@ -15,13 +14,15 @@ import * as UI from '../../ui/legacy/legacy.js';
15
14
  */
16
15
  export class ImagePreviewPopover {
17
16
  private readonly getLinkElement: (arg0: Event) => Element | null;
18
- private readonly getDOMNode: (arg0: Element) => SDK.DOMModel.DOMNode | null;
19
17
  private readonly popover: UI.PopoverHelper.PopoverHelper;
18
+
19
+ #getNodeFeatures: (link: Element) => Promise<Components.ImagePreview.PrecomputedFeatures|undefined>;
20
+
20
21
  constructor(
21
22
  container: HTMLElement, getLinkElement: (arg0: Event) => Element | null,
22
- getDOMNode: (arg0: Element) => SDK.DOMModel.DOMNode | null) {
23
+ getNodeFeatures: (arg0: Element) => Promise<Components.ImagePreview.PrecomputedFeatures|undefined>) {
23
24
  this.getLinkElement = getLinkElement;
24
- this.getDOMNode = getDOMNode;
25
+ this.#getNodeFeatures = getNodeFeatures;
25
26
  this.popover =
26
27
  new UI.PopoverHelper.PopoverHelper(container, this.handleRequest.bind(this), 'elements.image-preview');
27
28
  this.popover.setTimeout(0, 100);
@@ -39,11 +40,7 @@ export class ImagePreviewPopover {
39
40
  return {
40
41
  box: link.boxInWindow(),
41
42
  show: async (popover: UI.GlassPane.GlassPane) => {
42
- const node = this.getDOMNode((link));
43
- if (!node) {
44
- return false;
45
- }
46
- const precomputedFeatures = await Components.ImagePreview.ImagePreview.loadDimensionsForNode(node);
43
+ const precomputedFeatures = await this.#getNodeFeatures(link);
47
44
  const preview = await Components.ImagePreview.ImagePreview.build(href, true, {
48
45
  precomputedFeatures,
49
46
  align: Components.ImagePreview.Align.CENTER,
@@ -807,6 +807,7 @@ export class StylePropertiesSection {
807
807
  let scopeIndex = 0;
808
808
  let supportsIndex = 0;
809
809
  let nestingIndex = 0;
810
+ let navigationsIndex = 0;
810
811
  this.nestingLevel = 0;
811
812
  for (const ruleType of rule.ruleTypes) {
812
813
  let ancestorRuleElement;
@@ -829,6 +830,9 @@ export class StylePropertiesSection {
829
830
  case Protocol.CSS.CSSRuleType.StartingStyleRule:
830
831
  ancestorRuleElement = this.createStartingStyleElement();
831
832
  break;
833
+ case Protocol.CSS.CSSRuleType.NavigationRule:
834
+ ancestorRuleElement = this.createNavigationElement(rule.navigations[navigationsIndex++]);
835
+ break;
832
836
  }
833
837
  if (ancestorRuleElement) {
834
838
  this.#ancestorRuleListElement.prepend(ancestorRuleElement);
@@ -1007,6 +1011,27 @@ export class StylePropertiesSection {
1007
1011
  return supportsElement;
1008
1012
  }
1009
1013
 
1014
+ protected createNavigationElement(navigation: SDK.CSSNavigation.CSSNavigation): ElementsComponents.CSSQuery.CSSQuery
1015
+ |undefined {
1016
+ if (!navigation.text) {
1017
+ return;
1018
+ }
1019
+
1020
+ let onQueryTextClick;
1021
+ if (navigation.styleSheetId) {
1022
+ onQueryTextClick = this.handleQueryRuleClick.bind(this, navigation);
1023
+ }
1024
+
1025
+ const navigationElement = new ElementsComponents.CSSQuery.CSSQuery();
1026
+ navigationElement.data = {
1027
+ queryPrefix: '@navigation',
1028
+ queryText: navigation.text,
1029
+ onQueryTextClick,
1030
+ jslogContext: 'navigation',
1031
+ };
1032
+ return navigationElement;
1033
+ }
1034
+
1010
1035
  protected createNestingElement(nestingSelector?: string): HTMLElement|undefined {
1011
1036
  if (!nestingSelector) {
1012
1037
  return;
@@ -1419,6 +1444,8 @@ export class StylePropertiesSection {
1419
1444
  success = await cssModel.setSupportsText(query.styleSheetId, range, newContent);
1420
1445
  } else if (query instanceof SDK.CSSScope.CSSScope) {
1421
1446
  success = await cssModel.setScopeText(query.styleSheetId, range, newContent);
1447
+ } else if (query instanceof SDK.CSSNavigation.CSSNavigation) {
1448
+ success = await cssModel.setNavigationText(query.styleSheetId, range, newContent);
1422
1449
  } else {
1423
1450
  success = await cssModel.setMediaText(query.styleSheetId, range, newContent);
1424
1451
  }
@@ -1871,6 +1898,9 @@ export class FunctionRuleSection extends StylePropertiesSection {
1871
1898
  if ('supports' in condition) {
1872
1899
  return this.createSupportsElement(condition.supports);
1873
1900
  }
1901
+ if ('navigation' in condition) {
1902
+ return this.createNavigationElement(condition.navigation);
1903
+ }
1874
1904
  return;
1875
1905
  }
1876
1906
 
@@ -236,13 +236,19 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
236
236
  this.contentElement.addEventListener('copy', this.clipboardCopy.bind(this));
237
237
 
238
238
  this.boundOnScroll = this.onScroll.bind(this);
239
- this.imagePreviewPopover = new ImagePreviewPopover(this.contentElement, event => {
240
- const link = event.composedPath()[0];
241
- if (link instanceof Element) {
242
- return link;
243
- }
244
- return null;
245
- }, () => this.node());
239
+ this.imagePreviewPopover = new ImagePreviewPopover(
240
+ this.contentElement,
241
+ event => {
242
+ const link = event.composedPath()[0];
243
+ if (link instanceof Element) {
244
+ return link;
245
+ }
246
+ return null;
247
+ },
248
+ async () => {
249
+ const features = await Components.ImagePreview.loadPrecomputedFeatures(this.node());
250
+ return features;
251
+ });
246
252
 
247
253
  UI.ViewManager.ViewManager.instance().addEventListener(UI.ViewManager.Events.VIEW_VISIBILITY_CHANGED, event => {
248
254
  if (event.data.revealedViewId === 'animations' || event.data.hiddenViewId === 'animations') {
@@ -110,9 +110,13 @@ const UIStrings = {
110
110
  /**
111
111
  * @description Title of a setting under the Elements category. Whether to show/hide code comments in HTML.
112
112
  */
113
+ htmlComments: 'HTML comments',
114
+ /**
115
+ * @description Title of an option under the Elements category that can be invoked through the Command Menu
116
+ */
113
117
  showHtmlComments: 'Show `HTML` comments',
114
118
  /**
115
- * @description Title of a setting under the Elements category. Whether to show/hide code comments in HTML.
119
+ * @description Title of an option under the Elements category that can be invoked through the Command Menu
116
120
  */
117
121
  hideHtmlComments: 'Hide `HTML` comments',
118
122
  /**
@@ -126,12 +130,12 @@ const UIStrings = {
126
130
  * the inspect tooltip (an information pane that hovers next to selected DOM elements) has extra
127
131
  * detail.
128
132
  */
129
- showDetailedInspectTooltip: 'Show detailed inspect tooltip',
133
+ detailedInspectTooltip: 'Detailed inspect tooltip',
130
134
  /**
131
135
  * @description Title of a setting under the Elements category in Settings. Turns on a mode where
132
136
  * hovering over CSS properties in the Styles pane will display a popover with documentation.
133
137
  */
134
- showCSSDocumentationTooltip: 'Show CSS documentation tooltip',
138
+ CSSDocumentationTooltip: 'CSS documentation tooltip',
135
139
  /**
136
140
  * @description A context menu item (command) in the Elements panel that copy the styles of
137
141
  * the HTML element.
@@ -146,7 +150,7 @@ const UIStrings = {
146
150
  * @description Title of a setting under the Elements category. Whether to show/hide hide
147
151
  * the shadow DOM nodes of HTML elements that are built into the browser (e.g. the <input> element).
148
152
  */
149
- showUserAgentShadowDOM: 'Show user agent shadow `DOM`',
153
+ userAgentShadowDOM: 'User agent shadow `DOM`',
150
154
  /**
151
155
  * @description Command for showing the 'Computed' tool. Displays computed CSS styles in Elements sidebar.
152
156
  */
@@ -489,7 +493,7 @@ Common.Settings.registerSettingExtension({
489
493
  category: Common.Settings.SettingCategory.ELEMENTS,
490
494
  storageType: Common.Settings.SettingStorageType.SYNCED,
491
495
  order: 1,
492
- title: i18nLazyString(UIStrings.showUserAgentShadowDOM),
496
+ title: i18nLazyString(UIStrings.userAgentShadowDOM),
493
497
  settingName: 'show-ua-shadow-dom',
494
498
  settingType: Common.Settings.SettingType.BOOLEAN,
495
499
  defaultValue: false,
@@ -528,7 +532,7 @@ Common.Settings.registerSettingExtension({
528
532
  category: Common.Settings.SettingCategory.ELEMENTS,
529
533
  storageType: Common.Settings.SettingStorageType.SYNCED,
530
534
  order: 3,
531
- title: i18nLazyString(UIStrings.showHtmlComments),
535
+ title: i18nLazyString(UIStrings.htmlComments),
532
536
  settingName: 'show-html-comments',
533
537
  settingType: Common.Settings.SettingType.BOOLEAN,
534
538
  defaultValue: true,
@@ -558,7 +562,7 @@ Common.Settings.registerSettingExtension({
558
562
  category: Common.Settings.SettingCategory.ELEMENTS,
559
563
  storageType: Common.Settings.SettingStorageType.SYNCED,
560
564
  order: 5,
561
- title: i18nLazyString(UIStrings.showDetailedInspectTooltip),
565
+ title: i18nLazyString(UIStrings.detailedInspectTooltip),
562
566
  settingName: 'show-detailed-inspect-tooltip',
563
567
  settingType: Common.Settings.SettingType.BOOLEAN,
564
568
  defaultValue: true,
@@ -581,7 +585,7 @@ Common.Settings.registerSettingExtension({
581
585
  Common.Settings.registerSettingExtension({
582
586
  category: Common.Settings.SettingCategory.ELEMENTS,
583
587
  storageType: Common.Settings.SettingStorageType.SYNCED,
584
- title: i18nLazyString(UIStrings.showCSSDocumentationTooltip),
588
+ title: i18nLazyString(UIStrings.CSSDocumentationTooltip),
585
589
  settingName: 'show-css-property-documentation-on-hover',
586
590
  settingType: Common.Settings.SettingType.BOOLEAN,
587
591
  defaultValue: true,