chrome-devtools-frontend 1.0.1596535 → 1.0.1597624

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 (101) hide show
  1. package/agents/prompts/ui-widgets.md +7 -8
  2. package/docs/ui_engineering.md +10 -11
  3. package/front_end/core/host/AidaClient.ts +4 -0
  4. package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -0
  5. package/front_end/core/host/UserMetrics.ts +12 -0
  6. package/front_end/core/root/Runtime.ts +5 -0
  7. package/front_end/core/sdk/CPUThrottlingManager.ts +14 -13
  8. package/front_end/core/sdk/CSSMatchedStyles.ts +2 -0
  9. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +28 -0
  10. package/front_end/core/sdk/PageResourceLoader.ts +22 -1
  11. package/front_end/devtools_compatibility.js +2 -1
  12. package/front_end/models/ai_assistance/AiConversation.ts +29 -8
  13. package/front_end/models/ai_assistance/ChangeManager.ts +16 -0
  14. package/front_end/models/ai_assistance/ExtensionScope.ts +11 -3
  15. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +127 -0
  16. package/front_end/models/ai_assistance/agents/AiAgent.ts +26 -3
  17. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +1 -1
  18. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +11 -8
  19. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +24 -0
  20. package/front_end/models/ai_assistance/agents/StylingAgent.ts +323 -16
  21. package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
  22. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +27 -0
  23. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +21 -0
  24. package/front_end/models/greendev/Prototypes.ts +7 -1
  25. package/front_end/models/trace/Processor.ts +1 -0
  26. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -0
  27. package/front_end/models/trace/insights/CharacterSet.ts +172 -0
  28. package/front_end/models/trace/insights/Models.ts +1 -0
  29. package/front_end/models/trace/insights/types.ts +1 -0
  30. package/front_end/models/trace/types/TraceEvents.ts +17 -0
  31. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +51 -36
  32. package/front_end/panels/ai_assistance/PatchWidget.ts +6 -6
  33. package/front_end/panels/ai_assistance/components/ChatMessage.ts +93 -74
  34. package/front_end/panels/ai_assistance/components/ChatView.ts +6 -11
  35. package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +18 -9
  36. package/front_end/panels/ai_assistance/components/StylingAgentMarkdownRenderer.ts +200 -0
  37. package/front_end/panels/ai_assistance/components/chatMessage.css +11 -8
  38. package/front_end/panels/application/AppManifestView.ts +3 -4
  39. package/front_end/panels/application/DeviceBoundSessionsView.ts +18 -22
  40. package/front_end/panels/application/FrameDetailsView.ts +9 -15
  41. package/front_end/panels/application/OriginTrialTreeView.ts +2 -3
  42. package/front_end/panels/application/ReportingApiView.ts +13 -17
  43. package/front_end/panels/application/ServiceWorkerCacheViews.ts +1 -1
  44. package/front_end/panels/application/components/BackForwardCacheView.ts +3 -3
  45. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +2 -3
  46. package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +3 -2
  47. package/front_end/panels/changes/ChangesView.ts +6 -4
  48. package/front_end/panels/common/ExtensionServer.ts +15 -0
  49. package/front_end/panels/console/ConsolePinPane.ts +3 -3
  50. package/front_end/panels/coverage/CoverageListView.ts +1 -1
  51. package/front_end/panels/css_overview/CSSOverviewPanel.ts +11 -15
  52. package/front_end/panels/developer_resources/DeveloperResourcesView.ts +3 -5
  53. package/front_end/panels/elements/ElementsTreeElement.ts +55 -47
  54. package/front_end/panels/elements/ElementsTreeOutline.ts +149 -28
  55. package/front_end/panels/elements/EventListenersWidget.ts +3 -2
  56. package/front_end/panels/elements/StandaloneStylesContainer.ts +21 -6
  57. package/front_end/panels/elements/StylePropertyTreeElement.ts +49 -4
  58. package/front_end/panels/layer_viewer/Layers3DView.ts +5 -4
  59. package/front_end/panels/lighthouse/LighthousePanel.ts +8 -0
  60. package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +5 -6
  61. package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +6 -11
  62. package/front_end/panels/network/RequestCookiesView.ts +3 -4
  63. package/front_end/panels/network/RequestInitiatorView.ts +7 -5
  64. package/front_end/panels/network/RequestResponseView.ts +10 -15
  65. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +3 -4
  66. package/front_end/panels/recorder/components/RecordingView.ts +31 -36
  67. package/front_end/panels/recorder/components/StepEditor.ts +6 -7
  68. package/front_end/panels/search/SearchView.ts +2 -3
  69. package/front_end/panels/settings/SettingsScreen.ts +3 -2
  70. package/front_end/panels/settings/WorkspaceSettingsTab.ts +2 -5
  71. package/front_end/panels/timeline/components/LiveMetricsView.ts +5 -8
  72. package/front_end/panels/timeline/components/insights/Cache.ts +8 -10
  73. package/front_end/panels/timeline/components/insights/CharacterSet.ts +38 -0
  74. package/front_end/panels/timeline/components/insights/DOMSize.ts +16 -20
  75. package/front_end/panels/timeline/components/insights/DocumentLatency.ts +2 -6
  76. package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +3 -4
  77. package/front_end/panels/timeline/components/insights/FontDisplay.ts +3 -4
  78. package/front_end/panels/timeline/components/insights/ForcedReflow.ts +5 -7
  79. package/front_end/panels/timeline/components/insights/INPBreakdown.ts +3 -4
  80. package/front_end/panels/timeline/components/insights/ImageDelivery.ts +3 -4
  81. package/front_end/panels/timeline/components/insights/ImageRef.ts +2 -4
  82. package/front_end/panels/timeline/components/insights/InsightRenderer.ts +2 -0
  83. package/front_end/panels/timeline/components/insights/LCPBreakdown.ts +5 -7
  84. package/front_end/panels/timeline/components/insights/LCPDiscovery.ts +2 -4
  85. package/front_end/panels/timeline/components/insights/LegacyJavaScript.ts +3 -4
  86. package/front_end/panels/timeline/components/insights/ModernHTTP.ts +3 -4
  87. package/front_end/panels/timeline/components/insights/NetworkDependencyTree.ts +7 -11
  88. package/front_end/panels/timeline/components/insights/NodeLink.ts +2 -4
  89. package/front_end/panels/timeline/components/insights/RenderBlocking.ts +3 -4
  90. package/front_end/panels/timeline/components/insights/SlowCSSSelector.ts +7 -10
  91. package/front_end/panels/timeline/components/insights/ThirdParties.ts +5 -7
  92. package/front_end/panels/timeline/components/insights/insights.ts +2 -0
  93. package/front_end/panels/web_audio/WebAudioView.ts +3 -4
  94. package/front_end/ui/components/settings/SettingCheckbox.ts +2 -0
  95. package/front_end/ui/legacy/UIUtils.ts +5 -5
  96. package/front_end/ui/legacy/Widget.ts +33 -2
  97. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
  98. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +8 -8
  99. package/front_end/ui/visual_logging/Debugging.ts +0 -32
  100. package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
  101. package/package.json +1 -1
@@ -1024,6 +1024,46 @@ export class ColorMixRenderer extends rendererBase(SDK.CSSPropertyParserMatchers
1024
1024
  }
1025
1025
  }
1026
1026
 
1027
+ // clang-format off
1028
+ export class ContrastColorRenderer extends rendererBase(SDK.CSSPropertyParserMatchers.ContrastColorMatch) {
1029
+ // clang-format on
1030
+ readonly #treeElement: StylePropertyTreeElement|null;
1031
+ readonly #stylesContainer: StylesContainer;
1032
+ constructor(stylesContainer: StylesContainer, treeElement: StylePropertyTreeElement|null) {
1033
+ super();
1034
+ this.#treeElement = treeElement;
1035
+ this.#stylesContainer = stylesContainer;
1036
+ }
1037
+
1038
+ override render(match: SDK.CSSPropertyParserMatchers.ContrastColorMatch, context: RenderingContext): Node[] {
1039
+ const content = document.createElement('span');
1040
+ content.appendChild(document.createTextNode('contrast-color('));
1041
+ const param = content.appendChild(document.createElement('span'));
1042
+ content.appendChild(document.createTextNode(')'));
1043
+ Renderer.renderInto(match.color, context, param);
1044
+
1045
+ if (context.matchedResult.hasUnresolvedSubstitutions(match.node)) {
1046
+ return [content];
1047
+ }
1048
+
1049
+ const colorText = context.matchedResult.getComputedText(match.node);
1050
+ const fakeSpan = document.body.appendChild(document.createElement('span'));
1051
+ fakeSpan.style.color = colorText;
1052
+ const resolvedColorText = window.getComputedStyle(fakeSpan).color;
1053
+ fakeSpan.remove();
1054
+
1055
+ const color = Common.Color.parse(resolvedColorText);
1056
+ if (!color) {
1057
+ return [content];
1058
+ }
1059
+
1060
+ const colorSwatch = new ColorRenderer(this.#stylesContainer, this.#treeElement).renderColorSwatch(color, content);
1061
+ context.addControl('color', colorSwatch);
1062
+
1063
+ return [colorSwatch, content];
1064
+ }
1065
+ }
1066
+
1027
1067
  // clang-format off
1028
1068
  export class AngleRenderer extends rendererBase(SDK.CSSPropertyParserMatchers.AngleMatch) {
1029
1069
  // clang-format on
@@ -1490,7 +1530,8 @@ export class ShadowRenderer extends rendererBase(SDK.CSSPropertyParserMatchers.S
1490
1530
  properties.push({value, source, propertyType: ShadowPropertyType.INSET, expansionContext});
1491
1531
  } else if (
1492
1532
  match instanceof SDK.CSSPropertyParserMatchers.ColorMatch ||
1493
- match instanceof SDK.CSSPropertyParserMatchers.ColorMixMatch) {
1533
+ match instanceof SDK.CSSPropertyParserMatchers.ColorMixMatch ||
1534
+ match instanceof SDK.CSSPropertyParserMatchers.ContrastColorMatch) {
1494
1535
  if (properties.find(({propertyType}) => propertyType === ShadowPropertyType.COLOR)) {
1495
1536
  return null;
1496
1537
  }
@@ -1950,6 +1991,7 @@ export function getPropertyRenderers(
1950
1991
  new VariableRenderer(stylesContainer, treeElement, matchedStyles, computedStyles, computedStyleExtraFields),
1951
1992
  new ColorRenderer(stylesContainer, treeElement),
1952
1993
  new ColorMixRenderer(stylesContainer, matchedStyles, computedStyles, computedStyleExtraFields, treeElement),
1994
+ new ContrastColorRenderer(stylesContainer, treeElement),
1953
1995
  new URLRenderer(style.parentRule, stylesContainer.node()),
1954
1996
  new AngleRenderer(treeElement),
1955
1997
  new LinkableNameRenderer(matchedStyles, stylesContainer),
@@ -2024,9 +2066,12 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
2024
2066
  this.listItemElement.textContent = '';
2025
2067
  }
2026
2068
 
2027
- this.property.addEventListener(SDK.CSSProperty.Events.LOCAL_VALUE_UPDATED, () => {
2028
- this.updateTitle();
2029
- });
2069
+ this.property.addEventListener(SDK.CSSProperty.Events.LOCAL_VALUE_UPDATED, this.updateTitle, this);
2070
+ }
2071
+
2072
+ override onunbind(): void {
2073
+ this.property.removeEventListener(SDK.CSSProperty.Events.LOCAL_VALUE_UPDATED, this.updateTitle, this);
2074
+ super.onunbind();
2030
2075
  }
2031
2076
 
2032
2077
  async gridNames(): Promise<Set<string>> {
@@ -27,6 +27,7 @@ import {
27
27
  import {Events as TransformControllerEvents, TransformController} from './TransformController.js';
28
28
 
29
29
  const {html, render, Directives: {ref}} = Lit;
30
+ const {widget} = UI.Widget;
30
31
 
31
32
  const UIStrings = {
32
33
  /**
@@ -108,11 +109,11 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
108
109
  ${layers3DViewStyles}
109
110
  </style>
110
111
  ${input.panelToolbar}
111
- ${input.error === 'missing-root' ? html`<div><devtools-widget .widgetConfig=${UI.Widget.widgetConfig(UI.EmptyWidget.EmptyWidget, {
112
+ ${input.error === 'missing-root' ? html`<div>${widget(UI.EmptyWidget.EmptyWidget, {
112
113
  header: i18nString(UIStrings.noLayerInformation),
113
114
  text: i18nString(UIStrings.layerExplanation)
114
- })}></devtools-widget></div>` : Lit.nothing}
115
- ${input.error === 'webgl-disabled' ? html`<div><devtools-widget .widgetConfig=${UI.Widget.widgetConfig(UI.EmptyWidget.EmptyWidget, {
115
+ })}</div>` : Lit.nothing}
116
+ ${input.error === 'webgl-disabled' ? html`<div>${widget(UI.EmptyWidget.EmptyWidget, {
116
117
  header: i18nString(UIStrings.cantDisplayLayers),
117
118
  text: i18nString(UIStrings.webglSupportIsDisabledInYour),
118
119
  extraElements: [
@@ -123,7 +124,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
123
124
  }
124
125
  )
125
126
  ],
126
- })}></devtools-widget></div>` : Lit.nothing}
127
+ })}</div>` : Lit.nothing}
127
128
  <canvas
128
129
  tabindex="0"
129
130
  jslog=${VisualLogging.canvas('layers').track({
@@ -63,6 +63,11 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
63
63
  let lighthousePanelInstace: LighthousePanel;
64
64
  type Nullable<T> = T|null;
65
65
 
66
+ export class ActiveLighthouseReport {
67
+ constructor(public report: LighthouseModel.ReporterTypes.ReportJSON) {
68
+ }
69
+ }
70
+
66
71
  export class LighthousePanel extends UI.Panel.Panel {
67
72
  private readonly controller: LighthouseController;
68
73
  private readonly startView: StartView;
@@ -108,6 +113,7 @@ export class LighthousePanel extends UI.Panel.Panel {
108
113
  this.renderStartView();
109
114
 
110
115
  this.controller.recomputePageAuditability();
116
+ UI.Context.Context.instance().setFlavor(ActiveLighthouseReport, null);
111
117
  }
112
118
 
113
119
  static instance(opts?: {forceNew: boolean, protocolService: ProtocolService, controller: LighthouseController}):
@@ -154,9 +160,11 @@ export class LighthousePanel extends UI.Panel.Panel {
154
160
  this.renderStatusView();
155
161
  const {lhr, artifacts} = await this.controller.collectLighthouseResults();
156
162
  this.buildReportUI(lhr, artifacts);
163
+ UI.Context.Context.instance().setFlavor(ActiveLighthouseReport, new ActiveLighthouseReport(lhr));
157
164
  return {report: lhr};
158
165
  } catch (err) {
159
166
  this.handleError(err);
167
+ UI.Context.Context.instance().setFlavor(ActiveLighthouseReport, null);
160
168
  return {report: null};
161
169
  }
162
170
  }
@@ -41,7 +41,7 @@ const UIStrings = {
41
41
  const str_ =
42
42
  i18n.i18n.registerUIStrings('panels/linear_memory_inspector/components/LinearMemoryInspector.ts', UIStrings);
43
43
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
44
- const {widgetConfig} = UI.Widget;
44
+ const {widget} = UI.Widget;
45
45
 
46
46
  /**
47
47
  * If the LinearMemoryInspector only receives a portion
@@ -162,13 +162,12 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: Record<string, unknown>,
162
162
  @addressinputchanged=${input.onAddressChange}
163
163
  @pagenavigation=${input.onNavigatePage}
164
164
  @historynavigation=${input.onNavigateHistory}></devtools-linear-memory-inspector-navigator>
165
- <devtools-widget .widgetConfig=${widgetConfig(LinearMemoryHighlightChipList, {
165
+ ${widget(LinearMemoryHighlightChipList, {
166
166
  highlightInfos: highlightedMemoryAreas,
167
167
  focusedMemoryHighlight,
168
168
  jumpToAddress: (address: number) => input.onJumpToAddress(address),
169
169
  deleteHighlight: input.onDeleteMemoryHighlight,
170
- })}>
171
- </devtools-widget>
170
+ })}
172
171
  <devtools-linear-memory-inspector-viewer
173
172
  .data=${
174
173
  {
@@ -186,7 +185,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: Record<string, unknown>,
186
185
  ${
187
186
  input.hideValueInspector ? nothing : html`
188
187
  <div class="value-interpreter">
189
- <devtools-widget .widgetConfig=${widgetConfig(LinearMemoryValueInterpreter, {
188
+ ${widget(LinearMemoryValueInterpreter, {
190
189
  buffer: input.memory
191
190
  .slice(
192
191
  input.address - input.memoryOffset,
@@ -201,7 +200,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: Record<string, unknown>,
201
200
  onJumpToAddressClicked: input.onJumpToAddress,
202
201
  onValueTypeToggled: input.onValueTypeToggled,
203
202
  onEndiannessChanged: input.onEndiannessChanged,
204
- })}></devtools-widget>
203
+ })}
205
204
  </div>`}
206
205
  `,
207
206
  target);
@@ -32,7 +32,7 @@ const str_ =
32
32
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
33
33
 
34
34
  const {render, html} = Lit;
35
- const {widgetConfig} = UI.Widget;
35
+ const {widget} = UI.Widget;
36
36
 
37
37
  export interface ViewInput {
38
38
  endianness: Endianness;
@@ -89,14 +89,10 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
89
89
  </div>
90
90
  <span class="divider"></span>
91
91
  <div>
92
- ${input.showSettings ?
93
- html`
94
- <devtools-widget .widgetConfig=${widgetConfig(ValueInterpreterSettings, {
95
- valueTypes: input.valueTypes, onToggle: input.onValueTypeToggled
96
- })}>
97
- </devtools-widget>` :
98
- html`
99
- <devtools-widget .widgetConfig=${widgetConfig(ValueInterpreterDisplay, {
92
+ ${input.showSettings
93
+ ? widget(ValueInterpreterSettings, {
94
+ valueTypes: input.valueTypes, onToggle: input.onValueTypeToggled})
95
+ : widget(ValueInterpreterDisplay, {
100
96
  buffer: input.buffer,
101
97
  valueTypes: input.valueTypes,
102
98
  endianness: input.endianness,
@@ -104,8 +100,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
104
100
  memoryLength: input.memoryLength,
105
101
  onValueTypeModeChange: input.onValueTypeModeChange,
106
102
  onJumpToAddressClicked: input.onJumpToAddressClicked,
107
- })}>
108
- </devtools-widget>`}
103
+ })}
109
104
  </div>
110
105
  </div>
111
106
  `,
@@ -14,6 +14,7 @@ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
14
14
 
15
15
  import requestCookiesViewStyles from './requestCookiesView.css.js';
16
16
  const {render, html} = Lit;
17
+ const {widget} = UI.Widget;
17
18
 
18
19
  const UIStrings = {
19
20
  /**
@@ -93,10 +94,8 @@ export const DEFAULT_VIEW: ViewFunction = (input, _output, target) => {
93
94
  <style>${requestCookiesViewStyles}</style>
94
95
  <style>${UI.inspectorCommonStyles}</style>
95
96
  <div class="request-cookies-view">
96
- ${input.gotCookies ? Lit.nothing : html`
97
- <devtools-widget .widgetConfig=${UI.Widget.widgetConfig(UI.EmptyWidget.EmptyWidget, {
98
- header: i18nString(UIStrings.thisRequestHasNoCookies)})}></devtools-widget>
99
- `}
97
+ ${input.gotCookies ? Lit.nothing : widget(UI.EmptyWidget.EmptyWidget, {
98
+ header: i18nString(UIStrings.thisRequestHasNoCookies)})}
100
99
 
101
100
  <div class=${input.requestCookies.cookies.length || input.hasBlockedCookies ? '' : 'hidden'}>
102
101
  <span class="request-cookies-title" title=${i18nString(UIStrings.cookiesThatWereSentToTheServerIn)}>
@@ -16,7 +16,7 @@ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
16
16
  import requestInitiatorViewStyles from './requestInitiatorView.css.js';
17
17
  import requestInitiatorViewTreeStyles from './requestInitiatorViewTree.css.js';
18
18
 
19
- const {widgetConfig} = UI.Widget;
19
+ const {widget} = UI.Widget;
20
20
 
21
21
  const UIStrings = {
22
22
  /**
@@ -59,19 +59,21 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
59
59
  if (!input.stackTrace) {
60
60
  return html`${nothing}`;
61
61
  }
62
+ // clang-format off
62
63
  return html`
63
64
  <li role="treeitem" class="request-initiator-view-section-title" aria-expanded="true" open>
64
65
  ${i18nString(UIStrings.requestCallStack)}
65
66
  <ul role="group">
66
67
  <li role="treeitem">
67
- <devtools-widget .widgetConfig=${widgetConfig(Components.JSPresentationUtils.StackTracePreviewContent, {
68
- options: {tabStops: true},
69
- stackTrace: input.stackTrace,
70
- })}></devtools-widget>
68
+ ${widget(Components.JSPresentationUtils.StackTracePreviewContent, {
69
+ options: {tabStops: true},
70
+ stackTrace: input.stackTrace,
71
+ })}
71
72
  </li>
72
73
  </ul>
73
74
  </li>
74
75
  `;
76
+ // clang-format on
75
77
  };
76
78
 
77
79
  const renderInitiatorNodes =
@@ -43,43 +43,38 @@ export interface ViewOutput {
43
43
  revealPosition: (position: SourceFrame.SourceFrame.RevealPosition) => Promise<void>;
44
44
  }
45
45
 
46
- const widgetConfig = UI.Widget.widgetConfig;
47
- const widgetRef = UI.Widget.widgetRef;
46
+ const {widgetConfig, widgetRef, widget} = UI.Widget;
48
47
  type View = (input: ViewInput, output: ViewOutput, target: HTMLElement) => void;
49
48
 
50
49
  export const DEFAULT_VIEW: View = (input: ViewInput, output: ViewOutput, target: HTMLElement): void => {
51
- let widget;
50
+ let widgetTemplate;
52
51
  if (TextUtils.StreamingContentData.isError(input.contentData)) {
53
52
  // clang-format off
54
- widget = html`<devtools-widget
55
- .widgetConfig=${widgetConfig(element => new UI.EmptyWidget.EmptyWidget(
53
+ widgetTemplate = html`${widget(element => new UI.EmptyWidget.EmptyWidget(
56
54
  i18nString(UIStrings.failedToLoadResponseData), (input.contentData as {error: string}).error,
57
- element))}></devtools-widget>`;
55
+ element))}`;
58
56
  // clang-format on
59
57
  } else if (input.request.statusCode === 204 || input.request.failed) {
60
58
  // clang-format off
61
- widget = html`<devtools-widget
62
- .widgetConfig=${widgetConfig(element => new UI.EmptyWidget.EmptyWidget(
59
+ widgetTemplate = html`${widget(element => new UI.EmptyWidget.EmptyWidget(
63
60
  i18nString(UIStrings.noPreview), i18nString(UIStrings.thisRequestHasNoResponseData),
64
- element))}></devtools-widget>`;
61
+ element))}`;
65
62
  // clang-format on
66
63
  } else if (input.renderAsText) {
67
64
  // clang-format off
68
- widget = html`<devtools-widget
69
- .widgetConfig=${widgetConfig(element => new SourceFrame.ResourceSourceFrame.SearchableContainer(
65
+ widgetTemplate = html`<devtools-widget .widgetConfig=${widgetConfig(element => new SourceFrame.ResourceSourceFrame.SearchableContainer(
70
66
  input.request, input.mimeType, element))}
71
67
  ${widgetRef(SourceFrame.ResourceSourceFrame.SearchableContainer, widget => {output.revealPosition = widget.revealPosition.bind(widget);})}></devtools-widget>`;
72
68
  // clang-format on
73
69
  } else {
74
70
  // clang-format off
75
- widget = html`<devtools-widget
76
- .widgetConfig=${widgetConfig(element => new BinaryResourceView(
71
+ widgetTemplate = html`${widget(element => new BinaryResourceView(
77
72
  input.contentData as TextUtils.StreamingContentData.StreamingContentData, input.request.url(),
78
- input.request.resourceType(), element))}></devtools-widget>`;
73
+ input.request.resourceType(), element))}`;
79
74
  // clang-format on
80
75
  }
81
76
 
82
- render(widget, target);
77
+ render(widgetTemplate, target);
83
78
  };
84
79
 
85
80
  export class RequestResponseView extends UI.Widget.VBox {
@@ -22,7 +22,7 @@ import {Events as JSONEditorEvents, JSONEditor, type Parameter} from './JSONEdit
22
22
  import protocolMonitorStyles from './protocolMonitor.css.js';
23
23
 
24
24
  const {styleMap} = Directives;
25
- const {widgetConfig, widgetRef} = UI.Widget;
25
+ const {widget, widgetConfig, widgetRef} = UI.Widget;
26
26
  const UIStrings = {
27
27
  /**
28
28
  * @description Text for one or a group of functions
@@ -675,7 +675,7 @@ type InfoWidgetView = (input: InfoWidgetViewInput, output: undefined, target: HT
675
675
 
676
676
  const INFO_WIDGET_VIEW: InfoWidgetView = (input, _output, target) => {
677
677
  // clang-format off
678
- render(html`<devtools-widget .widgetConfig=${widgetConfig(UI.TabbedPane.TabbedPane, {
678
+ render(widget(UI.TabbedPane.TabbedPane, {
679
679
  tabs: [
680
680
  {
681
681
  id: 'request',
@@ -696,8 +696,7 @@ const INFO_WIDGET_VIEW: InfoWidgetView = (input, _output, target) => {
696
696
  SourceFrame.JSONView.JSONView.createViewSync(input.response || null),
697
697
  selected: input.selectedTab === 'response',
698
698
  }
699
- ]})}>
700
- </devtools-widget>`, target);
699
+ ]}), target);
701
700
  // clang-format on
702
701
  };
703
702
 
@@ -37,6 +37,7 @@ import {
37
37
  } from './StepView.js';
38
38
 
39
39
  const {html} = Lit;
40
+ const {widget} = UI.Widget;
40
41
 
41
42
  const UIStrings = {
42
43
  /**
@@ -525,15 +526,12 @@ function renderReplayOrAbortButton(input: ViewInput): Lit.LitTemplate {
525
526
  }
526
527
 
527
528
  // clang-format off
528
- return html`<devtools-widget
529
- .widgetConfig=${UI.Widget.widgetConfig(ReplaySection, {
530
- settings: input.recorderSettings,
531
- replayExtensions: input.replayExtensions,
532
- onStartReplay: input.onTogglePlaying,
533
- disabled: input.replayState.isPlaying,
534
- })}
535
- >
536
- </devtools-widget>`;
529
+ return html`${widget(ReplaySection, {
530
+ settings: input.recorderSettings,
531
+ replayExtensions: input.replayExtensions,
532
+ onStartReplay: input.onTogglePlaying,
533
+ disabled: input.replayState.isPlaying,
534
+ })}`;
537
535
  // clang-format on
538
536
  }
539
537
 
@@ -571,32 +569,29 @@ function renderSections(input: ViewInput): Lit.LitTemplate {
571
569
  </div>
572
570
  <div class="content">
573
571
  <div class="steps">
574
- <devtools-widget
575
- .widgetConfig=${UI.Widget.widgetConfig(StepView, {
576
- section,
577
- state: input.getSectionState(section),
578
- isStartOfGroup: true,
579
- isEndOfGroup: section.steps.length === 0,
580
- isFirstSection: i === 0,
581
- isLastSection:
582
- i === input.sections.length - 1 &&
583
- section.steps.length === 0,
584
- isSelected:
585
- input.selectedStep === (section.causingStep || null),
586
- sectionIndex: i,
587
- isRecording: input.isRecording,
588
- isPlaying: input.replayState.isPlaying,
589
- error:
590
- input.getSectionState(section) === State.ERROR
591
- ? (input.currentError ?? undefined)
592
- : undefined,
593
- hasBreakpoint: false,
594
- removable: input.recording.steps.length > 1 && Boolean(section.causingStep),
595
- onStepClick: input.onStepClick,
596
- onStepHover: input.onStepHover,
597
- })}
598
- >
599
- </devtools-widget>
572
+ ${widget(StepView, {
573
+ section,
574
+ state: input.getSectionState(section),
575
+ isStartOfGroup: true,
576
+ isEndOfGroup: section.steps.length === 0,
577
+ isFirstSection: i === 0,
578
+ isLastSection:
579
+ i === input.sections.length - 1 &&
580
+ section.steps.length === 0,
581
+ isSelected:
582
+ input.selectedStep === (section.causingStep || null),
583
+ sectionIndex: i,
584
+ isRecording: input.isRecording,
585
+ isPlaying: input.replayState.isPlaying,
586
+ error:
587
+ input.getSectionState(section) === State.ERROR
588
+ ? (input.currentError ?? undefined)
589
+ : undefined,
590
+ hasBreakpoint: false,
591
+ removable: input.recording.steps.length > 1 && Boolean(section.causingStep),
592
+ onStepClick: input.onStepClick,
593
+ onStepHover: input.onStepHover,
594
+ })}
600
595
  ${section.steps.map(step => {
601
596
  const stepIndex = input.recording.steps.indexOf(step);
602
597
  return html`
@@ -653,7 +648,7 @@ function renderSections(input: ViewInput): Lit.LitTemplate {
653
648
  )}
654
649
  </div>
655
650
  `;
656
- // clang-format on
651
+ // clang-format on
657
652
  }
658
653
 
659
654
  function renderHeader(input: ViewInput): Lit.LitTemplate {
@@ -32,6 +32,7 @@ import {
32
32
  const {html, Decorators, Directives, LitElement} = Lit;
33
33
  const {customElement, property, state} = Decorators;
34
34
  const {live} = Directives;
35
+ const {widget} = UI.Widget;
35
36
 
36
37
  type StepFor<Type> = Extract<Models.Schema.Step, {type: Type}>;
37
38
  type Attribute = Keys<Models.Schema.Step>;
@@ -778,13 +779,11 @@ export class StepEditor extends LitElement {
778
779
  return html`<div class="attribute" data-attribute="selectors" jslog=${VisualLogging.treeItem('selectors')}>
779
780
  <div class="row">
780
781
  <div>selectors<span class="separator">:</span></div>
781
- <devtools-widget
782
- .widgetConfig=${UI.Widget.widgetConfig(SelectorPicker, {
783
- disabled: this.disabled,
784
- onSelectorPicked: this.#handleSelectorPicked,
785
- onAttributeRequested: this.#handleAttributeRequested,
786
- })}
787
- ></devtools-widget>
782
+ ${widget(SelectorPicker, {
783
+ disabled: this.disabled,
784
+ onSelectorPicked: this.#handleSelectorPicked,
785
+ onAttributeRequested: this.#handleAttributeRequested,
786
+ })}
788
787
  ${this.#renderDeleteButton('selectors')}
789
788
  </div>
790
789
  ${this.state.selectors.map((selector, index, selectors) => {
@@ -107,7 +107,7 @@ const UIStrings = {
107
107
  const str_ = i18n.i18n.registerUIStrings('panels/search/SearchView.ts', UIStrings);
108
108
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
109
109
  const {ref, live} = Directives;
110
- const {widgetConfig, widgetRef} = UI.Widget;
110
+ const {widgetConfig, widget, widgetRef} = UI.Widget;
111
111
 
112
112
  export interface SearchViewInput {
113
113
  query: string;
@@ -251,8 +251,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
251
251
  output.showAllMatches = () => void w.showAllMatches();
252
252
  output.collapseAllResults = () => void w.collapseAllResults(); })}>
253
253
  </devtools-widget>`
254
- : html`<devtools-widget .widgetConfig=${widgetConfig(UI.EmptyWidget.EmptyWidget, {header, text})}>
255
- </devtools-widget>`}
254
+ : widget(UI.EmptyWidget.EmptyWidget, {header, text})}
256
255
  </div>
257
256
  <div class="search-toolbar-summary" @keydown=${onPanelKeyDown}>
258
257
  <div class="search-message">${searchMessage}</div>
@@ -636,7 +636,7 @@ const GREENDEV_VIEW: View = (input, _output, target) => {
636
636
  <span>${i18nString(UIStrings.greenDevUnstable)}</span>
637
637
  </div>
638
638
  <div class="settings-experiments-block">
639
- ${renderPrototypeCheckboxes(input.settings, ['aiAnnotations', 'copyToGemini', 'breakpointDebuggerAgent'])}
639
+ ${renderPrototypeCheckboxes(input.settings, ['aiAnnotations', 'copyToGemini', 'breakpointDebuggerAgent', 'emulationCapabilities'])}
640
640
  </div>
641
641
  </devtools-card>
642
642
  </div>
@@ -647,7 +647,8 @@ const GREENDEV_VIEW: View = (input, _output, target) => {
647
647
  const GREENDEV_PROTOTYPE_NAMES: Record<keyof GreenDev.GreenDevSettings, string> = {
648
648
  aiAnnotations: 'AI auto-annotations',
649
649
  copyToGemini: 'Copy changes to AI Prompt',
650
- breakpointDebuggerAgent: 'Breakpoint Debugger Agent'
650
+ breakpointDebuggerAgent: 'Breakpoint Debugger Agent',
651
+ emulationCapabilities: 'Emulation Capabilities',
651
652
  };
652
653
 
653
654
  function renderPrototypeCheckboxes(
@@ -41,6 +41,7 @@ const UIStrings = {
41
41
  } as const;
42
42
  const str_ = i18n.i18n.registerUIStrings('panels/settings/WorkspaceSettingsTab.ts', UIStrings);
43
43
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
44
+ const {widget} = UI.Widget;
44
45
 
45
46
  export interface WorkspaceSettingsTabInput {
46
47
  excludePatternSetting: Common.Settings.RegExpSetting;
@@ -70,11 +71,7 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
70
71
  <devtools-card heading=${fileSystem.displayName}>
71
72
  <devtools-icon name="folder" slot="heading-prefix"></devtools-icon>
72
73
  <div class="mapping-view-container">
73
- <devtools-widget .widgetConfig=${
74
- UI.Widget.widgetConfig(
75
- EditFileSystemView,
76
- {fileSystem: fileSystem.fileSystem})}>
77
- </devtools-widget>
74
+ ${widget(EditFileSystemView, {fileSystem: fileSystem.fileSystem})}
78
75
  </div>
79
76
  <devtools-button
80
77
  slot="heading-suffix"
@@ -41,7 +41,7 @@ import metricValueStyles from './metricValueStyles.css.js';
41
41
  import {CLS_THRESHOLDS, INP_THRESHOLDS, renderMetricValue} from './Utils.js';
42
42
 
43
43
  const {html, nothing} = Lit;
44
- const {widgetConfig} = UI.Widget;
44
+ const {widget} = UI.Widget;
45
45
 
46
46
  type DeviceOption = CrUXManager.DeviceScope|'AUTO';
47
47
 
@@ -485,8 +485,7 @@ export class LiveMetricsView extends LegacyWrapper.LegacyWrapper.WrappableCompon
485
485
  <div class="related-info" slot="extra-info">
486
486
  <span class="related-info-label">${i18nString(UIStrings.lcpElement)}</span>
487
487
  <span class="related-info-link">
488
- <devtools-widget .widgetConfig=${widgetConfig(PanelsCommon.DOMLinkifier.DOMNodeLink, {node: this.#lcpValue?.nodeRef})}>
489
- </devtools-widget>
488
+ ${widget(PanelsCommon.DOMLinkifier.DOMNodeLink, {node: this.#lcpValue?.nodeRef})}
490
489
  </span>
491
490
  </div>
492
491
  `
@@ -650,7 +649,7 @@ export class LiveMetricsView extends LegacyWrapper.LegacyWrapper.WrappableCompon
650
649
  </ul>
651
650
  ` : nothing}
652
651
  <div class="environment-option">
653
- <devtools-widget .widgetConfig=${widgetConfig(CPUThrottlingSelector, {recommendedOption: recs.cpuOption})}></devtools-widget>
652
+ ${widget(CPUThrottlingSelector, {recommendedOption: recs.cpuOption})}
654
653
  </div>
655
654
  <div class="environment-option">
656
655
  <devtools-network-throttling-selector .recommendedConditions=${recs.networkConditions}></devtools-network-throttling-selector>
@@ -1003,8 +1002,7 @@ export class LiveMetricsView extends LegacyWrapper.LegacyWrapper.WrappableCompon
1003
1002
  : nothing}
1004
1003
  </span>
1005
1004
  <span class="interaction-node">
1006
- <devtools-widget .widgetConfig=${widgetConfig(PanelsCommon.DOMLinkifier.DOMNodeLink, {node: interaction.nodeRef})}>
1007
- </devtools-widget>
1005
+ ${widget(PanelsCommon.DOMLinkifier.DOMNodeLink, {node: interaction.nodeRef})}
1008
1006
  </span>
1009
1007
  ${isP98Excluded ? html`<devtools-icon
1010
1008
  class="interaction-info"
@@ -1113,8 +1111,7 @@ export class LiveMetricsView extends LegacyWrapper.LegacyWrapper.WrappableCompon
1113
1111
  <div class="layout-shift-nodes">
1114
1112
  ${layoutShift.affectedNodeRefs.map(node => html`
1115
1113
  <div class="layout-shift-node">
1116
- <devtools-widget .widgetConfig=${widgetConfig(PanelsCommon.DOMLinkifier.DOMNodeLink, {node})}>
1117
- </devtools-widget>
1114
+ ${widget(PanelsCommon.DOMLinkifier.DOMNodeLink, {node})}
1118
1115
  </div>
1119
1116
  `)}
1120
1117
  </div>
@@ -17,7 +17,7 @@ import {createLimitedRows, renderOthersLabel, Table, type TableDataRow} from './
17
17
  const {UIStrings, i18nString, createOverlayForRequest} = Trace.Insights.Models.Cache;
18
18
 
19
19
  const {html} = Lit;
20
- const {widgetConfig} = UI.Widget;
20
+ const {widget} = UI.Widget;
21
21
 
22
22
  export class Cache extends BaseInsightComponent<CacheInsightModel> {
23
23
  override internalName = 'cache';
@@ -58,15 +58,13 @@ export class Cache extends BaseInsightComponent<CacheInsightModel> {
58
58
  // clang-format off
59
59
  return html`
60
60
  <div class="insight-section">
61
- <devtools-widget
62
- .widgetConfig=${widgetConfig(Table, {
63
- data: {
64
- insight: this,
65
- headers: [i18nString(UIStrings.requestColumn), i18nString(UIStrings.cacheTTL)],
66
- rows,
67
- },
68
- })}>
69
- </devtools-widget>
61
+ ${widget(Table, {
62
+ data: {
63
+ insight: this,
64
+ headers: [i18nString(UIStrings.requestColumn), i18nString(UIStrings.cacheTTL)],
65
+ rows,
66
+ },
67
+ })}
70
68
  </div>`;
71
69
  // clang-format on
72
70
  }