chrome-devtools-frontend 1.0.1596535 → 1.0.1597448

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 (29) 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/InspectorFrontendHostAPI.ts +1 -0
  4. package/front_end/core/host/UserMetrics.ts +12 -0
  5. package/front_end/core/root/Runtime.ts +5 -0
  6. package/front_end/core/sdk/CPUThrottlingManager.ts +9 -12
  7. package/front_end/core/sdk/PageResourceLoader.ts +22 -1
  8. package/front_end/devtools_compatibility.js +2 -1
  9. package/front_end/models/ai_assistance/AiConversation.ts +5 -0
  10. package/front_end/models/ai_assistance/agents/AiAgent.ts +4 -0
  11. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +24 -0
  12. package/front_end/models/ai_assistance/agents/StylingAgent.ts +289 -12
  13. package/front_end/models/greendev/Prototypes.ts +7 -1
  14. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +35 -33
  15. package/front_end/panels/ai_assistance/PatchWidget.ts +6 -6
  16. package/front_end/panels/ai_assistance/components/ChatMessage.ts +3 -28
  17. package/front_end/panels/ai_assistance/components/ChatView.ts +6 -11
  18. package/front_end/panels/ai_assistance/components/StylingAgentMarkdownRenderer.ts +200 -0
  19. package/front_end/panels/ai_assistance/components/chatMessage.css +0 -8
  20. package/front_end/panels/application/ServiceWorkerCacheViews.ts +1 -1
  21. package/front_end/panels/common/ExtensionServer.ts +15 -0
  22. package/front_end/panels/elements/ElementsTreeElement.ts +55 -47
  23. package/front_end/panels/elements/ElementsTreeOutline.ts +149 -28
  24. package/front_end/panels/lighthouse/LighthousePanel.ts +8 -0
  25. package/front_end/panels/settings/SettingsScreen.ts +3 -2
  26. package/front_end/ui/legacy/UIUtils.ts +5 -5
  27. package/front_end/ui/legacy/Widget.ts +33 -2
  28. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  29. package/package.json +1 -1
@@ -90,6 +90,12 @@ interface ViewInput {
90
90
  omitRootDOMNode: boolean;
91
91
  selectEnabled: boolean;
92
92
  hideGutter: boolean;
93
+ maxTreeDepth?: number;
94
+ enableContextMenu?: boolean;
95
+ showComments?: boolean;
96
+ showAIButton?: boolean;
97
+ disableEdits?: boolean;
98
+ expandRoot?: boolean;
93
99
  visibleWidth?: number;
94
100
  visible?: boolean;
95
101
  wrap: boolean;
@@ -119,7 +125,9 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
119
125
  // FIXME: this is basically a ref to existing imperative
120
126
  // implementation. Once this is declarative the ref should not be
121
127
  // needed.
122
- output.elementsTreeOutline = new ElementsTreeOutline(input.omitRootDOMNode, input.selectEnabled, input.hideGutter);
128
+ output.elementsTreeOutline = new ElementsTreeOutline(
129
+ input.omitRootDOMNode, input.selectEnabled, input.hideGutter, input.maxTreeDepth, input.enableContextMenu,
130
+ input.showComments, input.showAIButton, input.disableEdits, input.expandRoot);
123
131
  output.elementsTreeOutline.addEventListener(
124
132
  ElementsTreeOutline.Events.SelectedNodeChanged, input.onSelectedNodeChanged, this);
125
133
  output.elementsTreeOutline.addEventListener(
@@ -128,6 +136,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
128
136
  output.elementsTreeOutline.addEventListener(UI.TreeOutline.Events.ElementCollapsed, input.onElementCollapsed, this);
129
137
  target.appendChild(output.elementsTreeOutline.element);
130
138
  }
139
+
131
140
  if (input.visibleWidth !== undefined) {
132
141
  output.elementsTreeOutline.setVisibleWidth(input.visibleWidth);
133
142
  }
@@ -209,6 +218,11 @@ export class DOMTreeWidget extends UI.Widget.Widget {
209
218
  onElementExpanded: () => void = () => {};
210
219
  onElementCollapsed: () => void = () => {};
211
220
 
221
+ #maxTreeDepth?: number;
222
+ #enableContextMenu = true;
223
+ #showComments = true;
224
+ #showAIButton = true;
225
+ #disableEdits = false;
212
226
  #visible = false;
213
227
  #visibleWidth?: number;
214
228
  #wrap = false;
@@ -232,6 +246,51 @@ export class DOMTreeWidget extends UI.Widget.Widget {
232
246
  return this.#viewOutput.elementsTreeOutline?.rootDOMNode ?? null;
233
247
  }
234
248
 
249
+ get maxTreeDepth(): number|undefined {
250
+ return this.#maxTreeDepth;
251
+ }
252
+
253
+ set maxTreeDepth(maxTreeDepth: number|undefined) {
254
+ this.#maxTreeDepth = maxTreeDepth;
255
+ this.performUpdate();
256
+ }
257
+
258
+ get enableContextMenu(): boolean {
259
+ return this.#enableContextMenu;
260
+ }
261
+
262
+ set enableContextMenu(enableContextMenu: boolean) {
263
+ this.#enableContextMenu = enableContextMenu;
264
+ this.performUpdate();
265
+ }
266
+
267
+ get showComments(): boolean {
268
+ return this.#showComments;
269
+ }
270
+
271
+ set showComments(showComments: boolean) {
272
+ this.#showComments = showComments;
273
+ this.performUpdate();
274
+ }
275
+
276
+ get showAIButton(): boolean {
277
+ return this.#showAIButton;
278
+ }
279
+
280
+ set showAIButton(showAIButton: boolean) {
281
+ this.#showAIButton = showAIButton;
282
+ this.performUpdate();
283
+ }
284
+
285
+ get disableEdits(): boolean {
286
+ return this.#disableEdits;
287
+ }
288
+
289
+ set disableEdits(disableEdits: boolean) {
290
+ this.#disableEdits = disableEdits;
291
+ this.performUpdate();
292
+ }
293
+
235
294
  #currentHighlightedNode: SDK.DOMModel.DOMNode|null = null;
236
295
 
237
296
  #view: View;
@@ -323,6 +382,11 @@ export class DOMTreeWidget extends UI.Widget.Widget {
323
382
  omitRootDOMNode: this.omitRootDOMNode,
324
383
  selectEnabled: this.selectEnabled,
325
384
  hideGutter: this.hideGutter,
385
+ maxTreeDepth: this.#maxTreeDepth,
386
+ enableContextMenu: this.#enableContextMenu,
387
+ showComments: this.#showComments,
388
+ showAIButton: this.#showAIButton,
389
+ disableEdits: this.#disableEdits,
326
390
  visibleWidth: this.#visibleWidth,
327
391
  visible: this.#visible,
328
392
  wrap: this.#wrap,
@@ -501,8 +565,17 @@ export class ElementsTreeOutline extends
501
565
  #issuesManager?: IssuesManager.IssuesManager.IssuesManager;
502
566
  #popupHelper?: UI.PopoverHelper.PopoverHelper;
503
567
  #nodeElementToIssues = new Map<Element, IssuesManager.Issue.Issue[]>();
504
-
505
- constructor(omitRootDOMNode?: boolean, selectEnabled?: boolean, hideGutter?: boolean) {
568
+ readonly maxTreeDepth?: number;
569
+ readonly enableContextMenu: boolean;
570
+ readonly showComments: boolean;
571
+ readonly showAIButton: boolean;
572
+ readonly disableEdits: boolean;
573
+ readonly expandRoot: boolean;
574
+
575
+ constructor(
576
+ omitRootDOMNode?: boolean, selectEnabled?: boolean, hideGutter?: boolean, maxTreeDepth?: number,
577
+ enableContextMenu?: boolean, showComments?: boolean, showAIButton?: boolean, disableEdits?: boolean,
578
+ expandRoot?: boolean) {
506
579
  super();
507
580
 
508
581
  this.#issuesManager = IssuesManager.IssuesManager.IssuesManager.instance();
@@ -516,26 +589,35 @@ export class ElementsTreeOutline extends
516
589
 
517
590
  this.elementInternal = this.element;
518
591
  this.elementInternal.classList.add('elements-tree-outline', 'source-code');
519
- if (hideGutter) {
520
- this.elementInternal.classList.add('elements-hide-gutter');
521
- }
592
+ this.maxTreeDepth = maxTreeDepth;
593
+ this.enableContextMenu = enableContextMenu ?? true;
594
+ this.showComments = showComments ?? true;
595
+ this.showAIButton = showAIButton ?? true;
596
+ this.disableEdits = disableEdits ?? false;
597
+ this.expandRoot = expandRoot ?? false;
598
+ this.elementInternal.classList.toggle('elements-hide-gutter', hideGutter);
522
599
  UI.ARIAUtils.setLabel(this.elementInternal, i18nString(UIStrings.pageDom));
523
600
  this.elementInternal.addEventListener('focusout', this.onfocusout.bind(this), false);
524
601
  this.elementInternal.addEventListener('mousedown', this.onmousedown.bind(this), false);
525
602
  this.elementInternal.addEventListener('mousemove', this.onmousemove.bind(this), false);
526
603
  this.elementInternal.addEventListener('mouseleave', this.onmouseleave.bind(this), false);
527
- this.elementInternal.addEventListener('dragstart', this.ondragstart.bind(this), false);
528
- this.elementInternal.addEventListener('dragover', this.ondragover.bind(this), false);
529
- this.elementInternal.addEventListener('dragleave', this.ondragleave.bind(this), false);
530
- this.elementInternal.addEventListener('drop', this.ondrop.bind(this), false);
531
- this.elementInternal.addEventListener('dragend', this.ondragend.bind(this), false);
532
- this.elementInternal.addEventListener('contextmenu', this.contextMenuEventFired.bind(this), false);
533
- this.elementInternal.addEventListener('clipboard-beforecopy', this.onBeforeCopy.bind(this), false);
534
- this.elementInternal.addEventListener('clipboard-copy', this.onCopyOrCut.bind(this, false), false);
535
- this.elementInternal.addEventListener('clipboard-cut', this.onCopyOrCut.bind(this, true), false);
536
- this.elementInternal.addEventListener('clipboard-paste', this.onPaste.bind(this), false);
537
604
  this.elementInternal.addEventListener('keydown', this.onKeyDown.bind(this), false);
538
605
 
606
+ if (!this.disableEdits) {
607
+ this.elementInternal.addEventListener('dragstart', this.ondragstart.bind(this), false);
608
+ this.elementInternal.addEventListener('dragover', this.ondragover.bind(this), false);
609
+ this.elementInternal.addEventListener('dragleave', this.ondragleave.bind(this), false);
610
+ this.elementInternal.addEventListener('drop', this.ondrop.bind(this), false);
611
+ this.elementInternal.addEventListener('dragend', this.ondragend.bind(this), false);
612
+ this.elementInternal.addEventListener('clipboard-beforecopy', this.onBeforeCopy.bind(this), false);
613
+ this.elementInternal.addEventListener('clipboard-copy', this.onCopyOrCut.bind(this, false), false);
614
+ this.elementInternal.addEventListener('clipboard-cut', this.onCopyOrCut.bind(this, true), false);
615
+ this.elementInternal.addEventListener('clipboard-paste', this.onPaste.bind(this), false);
616
+ }
617
+ if (this.enableContextMenu) {
618
+ this.elementInternal.addEventListener('contextmenu', this.contextMenuEventFired.bind(this), false);
619
+ }
620
+
539
621
  outlineDisclosureElement.appendChild(this.elementInternal);
540
622
  this.element = shadowContainer;
541
623
  this.contentElement.setAttribute('jslog', `${VisualLogging.tree('elements')}`);
@@ -571,9 +653,16 @@ export class ElementsTreeOutline extends
571
653
  this.treeElementsBeingUpdated = new Set();
572
654
 
573
655
  this.decoratorExtensions = null;
574
-
575
- this.showHTMLCommentsSetting = Common.Settings.Settings.instance().moduleSetting('show-html-comments');
576
- this.showHTMLCommentsSetting.addChangeListener(this.onShowHTMLCommentsChange.bind(this));
656
+ if (this.showComments) {
657
+ this.showHTMLCommentsSetting = Common.Settings.Settings.instance().moduleSetting('show-html-comments');
658
+ this.showHTMLCommentsSetting.addChangeListener(this.onShowHTMLCommentsChange.bind(this));
659
+ } else {
660
+ this.showHTMLCommentsSetting = {
661
+ get: () => false,
662
+ addChangeListener: () => {},
663
+ removeChangeListener: () => {},
664
+ } as unknown as Common.Settings.Setting<boolean>;
665
+ }
577
666
  this.setUseLightSelectionColor(true);
578
667
  // TODO(changhaohan): refactor the popover to use tooltip component.
579
668
  this.#popupHelper = new UI.PopoverHelper.PopoverHelper(this.elementInternal, event => {
@@ -595,19 +684,20 @@ export class ElementsTreeOutline extends
595
684
  render(html`
596
685
  <div class="squiggles-content">
597
686
  ${issues.map(issue => {
598
- const elementIssueDetails = getElementIssueDetails(issue);
599
- if (!elementIssueDetails) {
600
- // This shouldn't happen, but add this if check to pass ts check.
601
- return nothing;
602
- }
603
- const issueKindIconName = IssueCounter.IssueCounter.getIssueKindIconName(issue.getKind());
604
- const openIssueEvent = (): Promise<void> => Common.Revealer.reveal(issue);
605
- return html`
687
+ const elementIssueDetails = getElementIssueDetails(issue);
688
+ if (!elementIssueDetails) {
689
+ // This shouldn't happen, but add this if check to pass ts check.
690
+ return nothing;
691
+ }
692
+ const issueKindIconName = IssueCounter.IssueCounter.getIssueKindIconName(issue.getKind());
693
+ const openIssueEvent = (): Promise<void> => Common.Revealer.reveal(issue);
694
+ return html`
606
695
  <div class="squiggles-content-item">
607
696
  <devtools-icon .name=${issueKindIconName} @click=${openIssueEvent}></devtools-icon>
608
697
  <devtools-link class="link" @click=${openIssueEvent}>${i18nString(UIStrings.viewIssue)}</devtools-link>
609
698
  <span>${elementIssueDetails.tooltip}</span>
610
- </div>`;})}
699
+ </div>`;
700
+ })}
611
701
  </div>`, popover.contentElement);
612
702
  // clang-format on
613
703
  return true;
@@ -958,6 +1048,9 @@ export class ElementsTreeOutline extends
958
1048
  if (this.includeRootDOMNode) {
959
1049
  const treeElement = this.createElementTreeElement(this.rootDOMNode);
960
1050
  this.appendChild(treeElement);
1051
+ if (this.expandRoot) {
1052
+ treeElement.expand();
1053
+ }
961
1054
  } else {
962
1055
  // FIXME: this could use findTreeElement to reuse a tree element if it already exists
963
1056
  const children = this.visibleChildren(this.rootDOMNode);
@@ -1774,6 +1867,31 @@ export class ElementsTreeOutline extends
1774
1867
  }
1775
1868
  }
1776
1869
 
1870
+ private isMaxDepthReached(node: SDK.DOMModel.DOMNode): boolean {
1871
+ if (this.maxTreeDepth === undefined || this.maxTreeDepth === Infinity) {
1872
+ return false;
1873
+ }
1874
+ // Allow ShadowRoots and Documents to expand one more level.
1875
+ if (node.nodeType() === Node.DOCUMENT_NODE || node.isShadowRoot()) {
1876
+ return false;
1877
+ }
1878
+ const maxDepth = this.maxTreeDepth;
1879
+ let depth = 0;
1880
+ let current: SDK.DOMModel.DOMNode|null = node;
1881
+ const rootNode = this.rootDOMNode;
1882
+ while (current && current !== rootNode) {
1883
+ depth++;
1884
+ current = current.parentNode;
1885
+ }
1886
+ if (this.includeRootDOMNode) {
1887
+ depth++;
1888
+ }
1889
+ if (depth >= maxDepth) {
1890
+ return true;
1891
+ }
1892
+ return false;
1893
+ }
1894
+
1777
1895
  private createElementTreeElement(node: SDK.DOMModel.DOMNode|SDK.DOMModel.AdoptedStyleSheet[], isClosingTag?: boolean):
1778
1896
  UI.TreeOutline.TreeElement {
1779
1897
  if (node instanceof Array) {
@@ -1870,6 +1988,9 @@ export class ElementsTreeOutline extends
1870
1988
  }
1871
1989
 
1872
1990
  private hasVisibleChildren(node: SDK.DOMModel.DOMNode): boolean {
1991
+ if (this.isMaxDepthReached(node)) {
1992
+ return false;
1993
+ }
1873
1994
  if (node.isIframe()) {
1874
1995
  return true;
1875
1996
  }
@@ -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
  }
@@ -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(
@@ -2094,10 +2094,7 @@ export class HTMLElementWithLightDOMTemplate extends HTMLElement {
2094
2094
  const patchingWrapper = <Args extends any[], R>(fn: (...args: Args) => R): ((...args: Args) => R) => {
2095
2095
  return function(this: unknown, ...args: Args): R {
2096
2096
  const result = fn.apply(this, args);
2097
- if (isLitTemplate(result)) {
2098
- HTMLElementWithLightDOMTemplate.patchLitTemplate(result);
2099
- }
2100
- return result;
2097
+ return patchValue(result) as R;
2101
2098
  };
2102
2099
  };
2103
2100
  if (template === Lit.nothing) {
@@ -2117,7 +2114,10 @@ export class HTMLElementWithLightDOMTemplate extends HTMLElement {
2117
2114
 
2118
2115
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
2119
2116
  function isCallable(value: unknown): value is(...args: any[]) => any {
2120
- return typeof value === 'function';
2117
+ // Native class constructors cannot be invoked without 'new', and we shouldn't attempt to wrap them.
2118
+ // Differentiate them from regular functions by checking their 'prototype' descriptor:
2119
+ // class constructors have a non-writable prototype, whereas regular functions have a writable prototype.
2120
+ return typeof value === 'function' && Object.getOwnPropertyDescriptor(value, 'prototype')?.writable !== false;
2121
2121
  }
2122
2122
 
2123
2123
  function patchValue(value: unknown): unknown {
@@ -38,6 +38,8 @@ import * as Lit from '../../ui/lit/lit.js';
38
38
  import {appendStyle, deepActiveElement} from './DOMUtilities.js';
39
39
  import {cloneCustomElement, createShadowRootWithCoreStyles} from './UIUtils.js';
40
40
 
41
+ const {html} = Lit;
42
+
41
43
  // Remember the original DOM mutation methods here, since we
42
44
  // will override them below to sanity check the Widget system.
43
45
  const originalAppendChild = Element.prototype.appendChild;
@@ -223,7 +225,7 @@ export class WidgetElement<WidgetT extends Widget> extends HTMLElement {
223
225
  }
224
226
 
225
227
  override removeChild<T extends Node>(child: T): T {
226
- const childWidget = Widget.get(child as unknown as HTMLElement);
228
+ const childWidget = Widget.get(child);
227
229
  if (childWidget) {
228
230
  childWidget.detach();
229
231
  return child;
@@ -233,7 +235,7 @@ export class WidgetElement<WidgetT extends Widget> extends HTMLElement {
233
235
 
234
236
  override removeChildren(): void {
235
237
  for (const child of this.children) {
236
- const childWidget = Widget.get(child as unknown as HTMLElement);
238
+ const childWidget = Widget.get(child);
237
239
  if (childWidget) {
238
240
  childWidget.detach();
239
241
  }
@@ -263,6 +265,35 @@ export class WidgetElement<WidgetT extends Widget> extends HTMLElement {
263
265
 
264
266
  customElements.define('devtools-widget', WidgetElement);
265
267
 
268
+ export class WidgetDirective extends Lit.Directive.Directive {
269
+ constructor(partInfo: Lit.Directive.PartInfo) {
270
+ super(partInfo);
271
+ if (partInfo.type !== Lit.Directive.PartType.CHILD) {
272
+ throw new Error('Widget directive must be used as a child directive.');
273
+ }
274
+ }
275
+
276
+ render<F extends WidgetFactory<Widget>, ParamKeys extends keyof InferWidgetTFromFactory<F>>(
277
+ widgetClass: F,
278
+ widgetParams?: Pick<InferWidgetTFromFactory<F>, ParamKeys>&Partial<InferWidgetTFromFactory<F>>): unknown {
279
+ // We use `repeat` to force Lit to recreate the `<devtools-widget>` DOM node when the `widgetClass` changes.
280
+ // If we didn't use `repeat` and used `html` directly, Lit would reuse the same `<devtools-widget>` instance
281
+ // even if `widgetClass` changed (for example, in a ternary operator `condition ? widget(A) : widget(B)`).
282
+ // This is because the template string is the same, so Lit reuses the DOM node and only updates `.widgetConfig`,
283
+ // which does not properly recreate the widget instance.
284
+ return Lit.Directives.repeat(
285
+ [widgetClass], () => widgetClass,
286
+ () => html`<devtools-widget .widgetConfig=${
287
+ widgetConfig(widgetClass, widgetParams as never)}></devtools-widget>`);
288
+ }
289
+ }
290
+
291
+ export const widget = Lit.Directive.directive(WidgetDirective) as
292
+ <F extends WidgetFactory<Widget>, ParamKeys extends keyof InferWidgetTFromFactory<F>>(
293
+ widgetClass: F,
294
+ widgetParams?: Pick<InferWidgetTFromFactory<F>, ParamKeys>&
295
+ Partial<InferWidgetTFromFactory<F>>) => Lit.Directive.DirectiveResult<typeof WidgetDirective>;
296
+
266
297
  export function widgetRef<T extends Widget, Args extends unknown[]>(
267
298
  type: Platform.Constructor.Constructor<T, Args>, callback: (_: T) => void): ReturnType<typeof Lit.Directives.ref> {
268
299
  return Lit.Directives.ref((e?: Element) => {
@@ -1808,6 +1808,7 @@ export const knownContextValues = new Set([
1808
1808
  'greendev-artifact-viewer-enabled',
1809
1809
  'greendev-breakpoint-debugger-agent-enabled',
1810
1810
  'greendev-copy-to-gemini-enabled',
1811
+ 'greendev-emulation-capabilities-enabled',
1811
1812
  'greendev-in-devtools-floaty-enabled',
1812
1813
  'greendev-inline-widgets-enabled',
1813
1814
  'greendev-prototypes',
package/package.json CHANGED
@@ -105,5 +105,5 @@
105
105
  "flat-cache": "6.1.12"
106
106
  }
107
107
  },
108
- "version": "1.0.1596535"
108
+ "version": "1.0.1597448"
109
109
  }