chrome-devtools-frontend 1.0.1632065 → 1.0.1635876

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 (107) hide show
  1. package/front_end/core/host/UserMetrics.ts +5 -2
  2. package/front_end/core/root/ExperimentNames.ts +1 -0
  3. package/front_end/core/root/Runtime.ts +5 -0
  4. package/front_end/core/sdk/SourceMapCache.ts +13 -11
  5. package/front_end/core/sdk/SourceMapManager.ts +7 -3
  6. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +84 -22
  7. package/front_end/entrypoints/main/MainImpl.ts +8 -0
  8. package/front_end/generated/InspectorBackendCommands.ts +3 -4
  9. package/front_end/generated/SupportedCSSProperties.js +272 -2
  10. package/front_end/generated/protocol-mapping.d.ts +0 -10
  11. package/front_end/generated/protocol-proxy-api.d.ts +0 -8
  12. package/front_end/generated/protocol.ts +5 -7
  13. package/front_end/models/ai_assistance/AiConversation.ts +16 -11
  14. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +13 -2
  15. package/front_end/models/ai_assistance/agents/AiAgent.ts +65 -11
  16. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +42 -2
  17. package/front_end/models/ai_assistance/agents/GreenDevAgent.ts +68 -5
  18. package/front_end/models/ai_assistance/agents/GreenDevAgentAntigravityCliSocketClient.ts +53 -0
  19. package/front_end/models/ai_assistance/agents/GreenDevAgentGeminiCliSocketClient.ts +117 -0
  20. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +30 -1
  21. package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
  22. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +4 -2
  23. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +5 -2
  24. package/front_end/models/extensions/RecorderExtensionEndpoint.ts +9 -1
  25. package/front_end/models/extensions/RecorderPluginManager.ts +1 -0
  26. package/front_end/models/greendev/Prototypes.ts +17 -5
  27. package/front_end/models/trace/handlers/FramesHandler.ts +19 -13
  28. package/front_end/panels/ai_assistance/components/AccessibilityAgentMarkdownRenderer.ts +3 -0
  29. package/front_end/panels/ai_assistance/components/ChatInput.ts +4 -2
  30. package/front_end/panels/ai_assistance/components/ChatMessage.ts +3 -1
  31. package/front_end/panels/application/preloading/components/PreloadingString.ts +0 -8
  32. package/front_end/panels/common/ExtensionServer.ts +34 -11
  33. package/front_end/panels/elements/CSSRuleValidator.ts +37 -34
  34. package/front_end/panels/elements/CSSRuleValidatorHelper.ts +8 -6
  35. package/front_end/panels/elements/ElementsTreeElement.ts +8 -2
  36. package/front_end/panels/elements/components/CSSHintDetailsView.ts +5 -5
  37. package/front_end/panels/js_timeline/js_timeline-meta.ts +30 -0
  38. package/front_end/panels/protocol_monitor/JSONEditor.ts +4 -4
  39. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +2 -2
  40. package/front_end/panels/recorder/RecorderController.ts +50 -1
  41. package/front_end/panels/recorder/extensions/ExtensionManager.ts +1 -0
  42. package/front_end/panels/recorder/models/RecordingPlayer.ts +12 -3
  43. package/front_end/panels/recorder/testing/RecorderHelpers.ts +2 -0
  44. package/front_end/panels/settings/SettingsScreen.ts +3 -2
  45. package/front_end/panels/sources/FilteredUISourceCodeListProvider.ts +5 -2
  46. package/front_end/panels/timeline/timeline-meta.ts +10 -6
  47. package/front_end/panels/whats_new/ReleaseNoteText.ts +9 -9
  48. package/front_end/panels/whats_new/resources/WNDT.md +9 -9
  49. package/front_end/third_party/chromium/README.chromium +1 -1
  50. package/front_end/third_party/puppeteer/README.chromium +2 -2
  51. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +8 -5
  52. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +35 -33
  53. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.d.ts.map +1 -1
  54. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.js +0 -1
  55. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/TargetManager.js.map +1 -1
  56. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/WebMCP.d.ts.map +1 -1
  57. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/WebMCP.js +0 -3
  58. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/WebMCP.js.map +1 -1
  59. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts +8 -8
  60. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts.map +1 -1
  61. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js +8 -8
  62. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js.map +1 -1
  63. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts +1 -1
  64. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts.map +1 -1
  65. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js +1 -1
  66. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js.map +1 -1
  67. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.d.ts +2 -2
  68. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.d.ts.map +1 -1
  69. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.js +2 -1
  70. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/CustomQuerySelector.js.map +1 -1
  71. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/injected.d.ts +2 -7
  72. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/injected.d.ts.map +1 -1
  73. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/PuppeteerNode.d.ts +1 -1
  74. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/PuppeteerNode.js +1 -1
  75. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
  76. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
  77. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js.map +1 -1
  78. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.d.ts +10 -7
  79. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.d.ts.map +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.js +16 -12
  81. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/Mutex.js.map +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
  83. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
  84. package/front_end/third_party/puppeteer/package/lib/types.d.ts +8 -5
  85. package/front_end/third_party/puppeteer/package/package.json +5 -7
  86. package/front_end/third_party/puppeteer/package/src/cdp/TargetManager.ts +0 -1
  87. package/front_end/third_party/puppeteer/package/src/cdp/WebMCP.ts +0 -3
  88. package/front_end/third_party/puppeteer/package/src/common/Debug.ts +11 -11
  89. package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
  90. package/front_end/third_party/puppeteer/package/src/injected/CustomQuerySelector.ts +3 -2
  91. package/front_end/third_party/puppeteer/package/src/node/PuppeteerNode.ts +1 -1
  92. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  93. package/front_end/third_party/puppeteer/package/src/util/Mutex.ts +17 -12
  94. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  95. package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +7 -0
  96. package/front_end/ui/legacy/InspectorDrawerView.ts +2 -1
  97. package/front_end/ui/legacy/InspectorView.ts +1 -1
  98. package/front_end/ui/legacy/PlusButton.ts +269 -0
  99. package/front_end/ui/legacy/ViewManager.ts +38 -11
  100. package/front_end/ui/legacy/components/source_frame/FontView.ts +11 -3
  101. package/front_end/ui/legacy/components/source_frame/ImageView.ts +16 -0
  102. package/front_end/ui/legacy/components/source_frame/imageView.css +13 -0
  103. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -1
  104. package/front_end/ui/legacy/legacy.ts +2 -0
  105. package/front_end/ui/visual_logging/KnownContextValues.ts +21 -0
  106. package/mcp/mcp.ts +1 -1
  107. package/package.json +1 -10
@@ -1580,7 +1580,7 @@ export declare interface CookieData {
1580
1580
  /**
1581
1581
  * Cookie SameSite type.
1582
1582
  */
1583
- sameSite?: CookieSameSite;
1583
+ sameSite?: CookieSameSite_2;
1584
1584
  /**
1585
1585
  * Cookie expiration date, session cookie if not set
1586
1586
  */
@@ -1641,7 +1641,7 @@ export declare interface CookieParam {
1641
1641
  /**
1642
1642
  * Cookie SameSite type.
1643
1643
  */
1644
- sameSite?: CookieSameSite;
1644
+ sameSite?: CookieSameSite_2;
1645
1645
  /**
1646
1646
  * Cookie expiration date, session cookie if not set
1647
1647
  */
@@ -1704,7 +1704,8 @@ export declare type CookiePriority = 'Low' | 'Medium' | 'High';
1704
1704
  *
1705
1705
  * @public
1706
1706
  */
1707
- export declare type CookieSameSite = 'Strict' | 'Lax' | 'None' | 'Default';
1707
+ declare type CookieSameSite_2 = 'Strict' | 'Lax' | 'None' | 'Default';
1708
+ export type {CookieSameSite_2 as CookieSameSite};
1708
1709
 
1709
1710
  /**
1710
1711
  * Represents the source scheme of the origin that originally set the cookie. A value of
@@ -1889,6 +1890,7 @@ declare interface CustomQuerySelector {
1889
1890
 
1890
1891
  /**
1891
1892
  * This class mimics the injected {@link CustomQuerySelectorRegistry}.
1893
+ *
1892
1894
  */
1893
1895
  declare class CustomQuerySelectorRegistry {
1894
1896
  #private;
@@ -1900,6 +1902,7 @@ declare class CustomQuerySelectorRegistry {
1900
1902
 
1901
1903
  declare namespace CustomQuerySelectors {
1902
1904
  export type {CustomQuerySelector};
1905
+ export {CustomQuerySelectorRegistry};
1903
1906
  }
1904
1907
 
1905
1908
  /**
@@ -8249,7 +8252,7 @@ declare namespace Puppeteer_2 {
8249
8252
  ConnectOptions,
8250
8253
  ConsoleMessageLocation,
8251
8254
  ConsoleMessageType,
8252
- CookieSameSite,
8255
+ CookieSameSite_2 as CookieSameSite,
8253
8256
  CookiePriority,
8254
8257
  CookieSourceScheme,
8255
8258
  CookiePartitionKey,
@@ -8388,7 +8391,7 @@ export declare type PuppeteerLifeCycleEvent =
8388
8391
  * fetching and downloading browsers.
8389
8392
  *
8390
8393
  * If you're using Puppeteer in a Node environment, this is the class you'll get
8391
- * when you run `require('puppeteer')` (or the equivalent ES `import`).
8394
+ * when you run `import puppeteer from 'puppeteer'`.
8392
8395
  *
8393
8396
  * @remarks
8394
8397
  * The most common method to use is {@link PuppeteerNode.launch | launch}, which
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "puppeteer-core",
3
- "version": "25.0.4",
3
+ "version": "25.1.0",
4
4
  "description": "A high-level API to control headless Chrome over the DevTools Protocol",
5
5
  "keywords": [
6
6
  "puppeteer",
@@ -148,17 +148,15 @@
148
148
  "author": "The Chromium Authors",
149
149
  "license": "Apache-2.0",
150
150
  "dependencies": {
151
- "@puppeteer/browsers": "3.0.3",
151
+ "@puppeteer/browsers": "3.0.4",
152
152
  "chromium-bidi": "16.0.1",
153
- "debug": "^4.4.3",
154
- "devtools-protocol": "0.0.1608973",
153
+ "devtools-protocol": "0.0.1624250",
155
154
  "typed-query-selector": "^2.12.2",
156
- "webdriver-bidi-protocol": "0.4.1",
157
- "ws": "^8.20.0"
155
+ "webdriver-bidi-protocol": "0.4.2",
156
+ "ws": "^8.21.0"
158
157
  },
159
158
  "devDependencies": {
160
159
  "@types/chrome": "0.1.40",
161
- "@types/debug": "4.1.13",
162
160
  "@types/node": "^18.17.15",
163
161
  "@types/ws": "8.18.1",
164
162
  "mitt": "3.0.1",
@@ -548,7 +548,6 @@ export class TargetManager
548
548
  }
549
549
 
550
550
  await session.send('Network.emulateNetworkConditionsByRule', {
551
- // @ts-expect-error offline cannot be undefined before M149.
552
551
  offline: this.#blocklist.length > 0 ? true : undefined,
553
552
  matchedNetworkConditions,
554
553
  });
@@ -407,7 +407,6 @@ export class WebMCP extends EventEmitter<{
407
407
  tool: WebMCPTool,
408
408
  input: object,
409
409
  ): Promise<{invocationId: string}> {
410
- // @ts-expect-error WebMCP is not yet in the Protocol types.
411
410
  return await this.#client.send('WebMCP.invokeTool', {
412
411
  frameId: tool.frame._id,
413
412
  toolName: tool.name,
@@ -428,7 +427,6 @@ export class WebMCP extends EventEmitter<{
428
427
  this.#client.on('WebMCP.toolsAdded', this.#onToolsAdded);
429
428
  this.#client.on('WebMCP.toolsRemoved', this.#onToolsRemoved);
430
429
  this.#client.on('WebMCP.toolInvoked', this.#onToolInvoked);
431
- // @ts-expect-error M148 has non-final status type, update expected in M149
432
430
  this.#client.on('WebMCP.toolResponded', this.#onToolResponded);
433
431
  }
434
432
 
@@ -439,7 +437,6 @@ export class WebMCP extends EventEmitter<{
439
437
  this.#client.off('WebMCP.toolsAdded', this.#onToolsAdded);
440
438
  this.#client.off('WebMCP.toolsRemoved', this.#onToolsRemoved);
441
439
  this.#client.off('WebMCP.toolInvoked', this.#onToolInvoked);
442
- // @ts-expect-error M148 has non-final status type, update expected in M149
443
440
  this.#client.off('WebMCP.toolResponded', this.#onToolResponded);
444
441
  this.#client = client;
445
442
  this.#bindListeners();
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import type Debug from 'debug';
7
+ import type {debuglog} from 'node:util';
8
8
 
9
9
  import {isNode} from '../environment.js';
10
10
 
@@ -15,13 +15,13 @@ declare global {
15
15
  /**
16
16
  * @internal
17
17
  */
18
- let debugModule: typeof Debug | null = null;
18
+ let debugModule: typeof debuglog | null = null;
19
19
  /**
20
20
  * @internal
21
21
  */
22
- export async function importDebug(): Promise<typeof Debug> {
22
+ export async function importDebug(): Promise<typeof debuglog> {
23
23
  if (!debugModule) {
24
- debugModule = (await import('debug')).default;
24
+ debugModule = (await import('node:util')).debuglog;
25
25
  }
26
26
  return debugModule;
27
27
  }
@@ -30,16 +30,16 @@ export async function importDebug(): Promise<typeof Debug> {
30
30
  * A debug function that can be used in any environment.
31
31
  *
32
32
  * @remarks
33
- * If used in Node, it falls back to the
34
- * {@link https://www.npmjs.com/package/debug | debug module}. In the browser it
33
+ * If used in Node, it falls back to Node's built-in
34
+ * {@link https://nodejs.org/api/util.html#utildebuglogsection-callback | util.debuglog}. In the browser it
35
35
  * uses `console.log`.
36
36
  *
37
- * In Node, use the `DEBUG` environment variable to control logging:
37
+ * In Node, use the `NODE_DEBUG` environment variable to control logging:
38
38
  *
39
39
  * ```
40
- * DEBUG=* // logs all channels
41
- * DEBUG=foo // logs the `foo` channel
42
- * DEBUG=foo* // logs any channels starting with `foo`
40
+ * NODE_DEBUG=* // logs all channels
41
+ * NODE_DEBUG=foo // logs the `foo` channel
42
+ * NODE_DEBUG=foo* // logs any channels starting with `foo`
43
43
  * ```
44
44
  *
45
45
  * In the browser, set `window.__PUPPETEER_DEBUG` to a string:
@@ -70,7 +70,7 @@ export const debug = (prefix: string): ((...args: unknown[]) => void) => {
70
70
  if (captureLogs) {
71
71
  capturedLogs.push(prefix + logArgs);
72
72
  }
73
- (await importDebug())(prefix)(logArgs);
73
+ ((await importDebug())(prefix) as (...args: any[]) => void)(...logArgs);
74
74
  };
75
75
  }
76
76
 
@@ -5,4 +5,4 @@
5
5
  *
6
6
  * @internal
7
7
  */
8
- export const source = "\"use strict\";var g=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var Y=Object.prototype.hasOwnProperty;var l=(t,e)=>{for(var r in e)g(t,r,{get:e[r],enumerable:!0})},G=(t,e,r,o)=>{if(e&&typeof e==\"object\"||typeof e==\"function\")for(let s of B(e))!Y.call(t,s)&&s!==r&&g(t,s,{get:()=>e[s],enumerable:!(o=X(e,s))||o.enumerable});return t};var J=t=>G(g({},\"__esModule\",{value:!0}),t);var pe={};l(pe,{default:()=>he});module.exports=J(pe);var N=class extends Error{constructor(e,r){super(e,r),this.name=this.constructor.name}get[Symbol.toStringTag](){return this.constructor.name}},p=class extends N{};var c=class t{static create(e){return new t(e)}static async race(e){let r=new Set;try{let o=e.map(s=>s instanceof t?(s.#s&&r.add(s),s.valueOrThrow()):s);return await Promise.race(o)}finally{for(let o of r)o.reject(new Error(\"Timeout cleared\"))}}#e=!1;#r=!1;#o;#t;#a=new Promise(e=>{this.#t=e});#s;#i;constructor(e){e&&e.timeout>0&&(this.#i=new p(e.message),this.#s=setTimeout(()=>{this.reject(this.#i)},e.timeout))}#l(e){clearTimeout(this.#s),this.#o=e,this.#t()}resolve(e){this.#r||this.#e||(this.#e=!0,this.#l(e))}reject(e){this.#r||this.#e||(this.#r=!0,this.#l(e))}resolved(){return this.#e}finished(){return this.#e||this.#r}value(){return this.#o}#n;valueOrThrow(){return this.#n||(this.#n=(async()=>{if(await this.#a,this.#r)throw this.#o;return this.#o})()),this.#n}};var L=new Map,W=t=>{let e=L.get(t);return e||(e=new Function(`return ${t}`)(),L.set(t,e),e)};var b={};l(b,{ariaQuerySelector:()=>z,ariaQuerySelectorAll:()=>x});var z=(t,e)=>globalThis.__ariaQuerySelector(t,e),x=async function*(t,e){yield*await globalThis.__ariaQuerySelectorAll(t,e)};var E={};l(E,{cssQuerySelector:()=>K,cssQuerySelectorAll:()=>Z});var K=(t,e)=>t.querySelector(e),Z=function(t,e){return t.querySelectorAll(e)};var A={};l(A,{customQuerySelectors:()=>P});var v=class{#e=new Map;register(e,r){if(!r.queryOne&&r.queryAll){let o=r.queryAll;r.queryOne=(s,i)=>{for(let n of o(s,i))return n;return null}}else if(r.queryOne&&!r.queryAll){let o=r.queryOne;r.queryAll=(s,i)=>{let n=o(s,i);return n?[n]:[]}}else if(!r.queryOne||!r.queryAll)throw new Error(\"At least one query method must be defined.\");this.#e.set(e,{querySelector:r.queryOne,querySelectorAll:r.queryAll})}unregister(e){this.#e.delete(e)}get(e){return this.#e.get(e)}clear(){this.#e.clear()}},P=new v;var R={};l(R,{pierceQuerySelector:()=>ee,pierceQuerySelectorAll:()=>te});var ee=(t,e)=>{let r=null,o=s=>{let i=document.createTreeWalker(s,NodeFilter.SHOW_ELEMENT);do{let n=i.currentNode;n.shadowRoot&&o(n.shadowRoot),!(n instanceof ShadowRoot)&&n!==s&&!r&&n.matches(e)&&(r=n)}while(!r&&i.nextNode())};return t instanceof Document&&(t=t.documentElement),o(t),r},te=(t,e)=>{let r=[],o=s=>{let i=document.createTreeWalker(s,NodeFilter.SHOW_ELEMENT);do{let n=i.currentNode;n.shadowRoot&&o(n.shadowRoot),!(n instanceof ShadowRoot)&&n!==s&&n.matches(e)&&r.push(n)}while(i.nextNode())};return t instanceof Document&&(t=t.documentElement),o(t),r};var u=(t,e)=>{if(!t)throw new Error(e)};var y=class{#e;#r;#o;#t;constructor(e,r){this.#e=e,this.#r=r}async start(){let e=this.#t=c.create(),r=await this.#e();if(r){e.resolve(r);return}this.#o=new MutationObserver(async()=>{let o=await this.#e();o&&(e.resolve(o),await this.stop())}),this.#o.observe(this.#r,{childList:!0,subtree:!0,attributes:!0})}async stop(){u(this.#t,\"Polling never started.\"),this.#t.finished()||this.#t.reject(new Error(\"Polling stopped\")),this.#o&&(this.#o.disconnect(),this.#o=void 0)}result(){return u(this.#t,\"Polling never started.\"),this.#t.valueOrThrow()}},w=class{#e;#r;constructor(e){this.#e=e}async start(){let e=this.#r=c.create(),r=await this.#e();if(r){e.resolve(r);return}let o=async()=>{if(e.finished())return;let s=await this.#e();if(!s){window.requestAnimationFrame(o);return}e.resolve(s),await this.stop()};window.requestAnimationFrame(o)}async stop(){u(this.#r,\"Polling never started.\"),this.#r.finished()||this.#r.reject(new Error(\"Polling stopped\"))}result(){return u(this.#r,\"Polling never started.\"),this.#r.valueOrThrow()}},T=class{#e;#r;#o;#t;constructor(e,r){this.#e=e,this.#r=r}async start(){let e=this.#t=c.create(),r=await this.#e();if(r){e.resolve(r);return}this.#o=setInterval(async()=>{let o=await this.#e();o&&(e.resolve(o),await this.stop())},this.#r)}async stop(){u(this.#t,\"Polling never started.\"),this.#t.finished()||this.#t.reject(new Error(\"Polling stopped\")),this.#o&&(clearInterval(this.#o),this.#o=void 0)}result(){return u(this.#t,\"Polling never started.\"),this.#t.valueOrThrow()}};var _={};l(_,{PCombinator:()=>H,pQuerySelector:()=>fe,pQuerySelectorAll:()=>$});var a=class{static async*map(e,r){for await(let o of e)yield await r(o)}static async*flatMap(e,r){for await(let o of e)yield*r(o)}static async collect(e){let r=[];for await(let o of e)r.push(o);return r}static async first(e){for await(let r of e)return r}};var C={};l(C,{textQuerySelectorAll:()=>m});var re=new Set([\"checkbox\",\"image\",\"radio\"]),oe=t=>t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement||t instanceof HTMLInputElement&&!re.has(t.type),se=new Set([\"SCRIPT\",\"STYLE\"]),f=t=>!se.has(t.nodeName)&&!document.head?.contains(t),I=new WeakMap,F=t=>{for(;t;)I.delete(t),t instanceof ShadowRoot?t=t.host:t=t.parentNode},j=new WeakSet,ne=new MutationObserver(t=>{for(let e of t)F(e.target)}),d=t=>{let e=I.get(t);if(e||(e={full:\"\",immediate:[]},!f(t)))return e;let r=\"\";if(oe(t))e.full=t.value,e.immediate.push(t.value),t.addEventListener(\"input\",o=>{F(o.target)},{once:!0,capture:!0});else{for(let o=t.firstChild;o;o=o.nextSibling){if(o.nodeType===Node.TEXT_NODE){e.full+=o.nodeValue??\"\",r+=o.nodeValue??\"\";continue}r&&e.immediate.push(r),r=\"\",o.nodeType===Node.ELEMENT_NODE&&(e.full+=d(o).full)}r&&e.immediate.push(r),t instanceof Element&&t.shadowRoot&&(e.full+=d(t.shadowRoot).full),j.has(t)||(ne.observe(t,{childList:!0,characterData:!0,subtree:!0}),j.add(t))}return I.set(t,e),e};var m=function*(t,e){let r=!1;for(let o of t.childNodes)if(o instanceof Element&&f(o)){let s;o.shadowRoot?s=m(o.shadowRoot,e):s=m(o,e);for(let i of s)yield i,r=!0}r||t instanceof Element&&f(t)&&d(t).full.includes(e)&&(yield t)};var k={};l(k,{checkVisibility:()=>le,pierce:()=>S,pierceAll:()=>O});var ie=[\"hidden\",\"collapse\"],le=(t,e)=>{if(!t)return e===!1;if(e===void 0)return t;let r=t.nodeType===Node.TEXT_NODE?t.parentElement:t,o=window.getComputedStyle(r),s=o&&!ie.includes(o.visibility)&&!ae(r);return e===s?t:!1};function ae(t){let e=t.getBoundingClientRect();return e.width===0||e.height===0}var ce=t=>\"shadowRoot\"in t&&t.shadowRoot instanceof ShadowRoot;function*S(t){ce(t)?yield t.shadowRoot:yield t}function*O(t){t=S(t).next().value,yield t;let e=[document.createTreeWalker(t,NodeFilter.SHOW_ELEMENT)];for(let r of e){let o;for(;o=r.nextNode();)o.shadowRoot&&(yield o.shadowRoot,e.push(document.createTreeWalker(o.shadowRoot,NodeFilter.SHOW_ELEMENT)))}}var D={};l(D,{xpathQuerySelectorAll:()=>q});var q=function*(t,e,r=-1){let s=(t.ownerDocument||document).evaluate(e,t,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE),i=[],n;for(;(n=s.iterateNext())&&(i.push(n),!(r&&i.length===r)););for(let h=0;h<i.length;h++)n=i[h],yield n,i[h]=null};var ue=/[-\\w\\P{ASCII}*]/u,H=(r=>(r.Descendent=\">>>\",r.Child=\">>>>\",r))(H||{}),V=t=>\"querySelectorAll\"in t,Q=class{#e;#r=[];#o=void 0;elements;constructor(e,r){this.elements=[e],this.#e=r,this.#t()}async run(){for(typeof this.#o==\"string\"&&this.#o.trimStart()===\":scope\"&&this.#t();this.#o!==void 0;this.#t()){let e=this.#o;typeof e==\"string\"?e[0]&&ue.test(e[0])?this.elements=a.flatMap(this.elements,async function*(r){V(r)&&(yield*r.querySelectorAll(e))}):this.elements=a.flatMap(this.elements,async function*(r){if(!r.parentElement){if(!V(r))return;yield*r.querySelectorAll(e);return}let o=0;for(let s of r.parentElement.children)if(++o,s===r)break;yield*r.parentElement.querySelectorAll(`:scope>:nth-child(${o})${e}`)}):this.elements=a.flatMap(this.elements,async function*(r){switch(e.name){case\"text\":yield*m(r,e.value);break;case\"xpath\":yield*q(r,e.value);break;case\"aria\":yield*x(r,e.value);break;default:let o=P.get(e.name);if(!o)throw new Error(`Unknown selector type: ${e.name}`);yield*o.querySelectorAll(r,e.value)}})}}#t(){if(this.#r.length!==0){this.#o=this.#r.shift();return}if(this.#e.length===0){this.#o=void 0;return}let e=this.#e.shift();switch(e){case\">>>>\":{this.elements=a.flatMap(this.elements,S),this.#t();break}case\">>>\":{this.elements=a.flatMap(this.elements,O),this.#t();break}default:this.#r=e,this.#t();break}}},M=class{#e=new WeakMap;calculate(e,r=[]){if(e===null)return r;e instanceof ShadowRoot&&(e=e.host);let o=this.#e.get(e);if(o)return[...o,...r];let s=0;for(let n=e.previousSibling;n;n=n.previousSibling)++s;let i=this.calculate(e.parentNode,[s]);return this.#e.set(e,i),[...i,...r]}},U=(t,e)=>{if(t.length+e.length===0)return 0;let[r=-1,...o]=t,[s=-1,...i]=e;return r===s?U(o,i):r<s?-1:1},de=async function*(t){let e=new Set;for await(let o of t)e.add(o);let r=new M;yield*[...e.values()].map(o=>[o,r.calculate(o)]).sort(([,o],[,s])=>U(o,s)).map(([o])=>o)},$=function(t,e){let r=JSON.parse(e);if(r.some(o=>{let s=0;return o.some(i=>(typeof i==\"string\"?++s:s=0,s>1))}))throw new Error(\"Multiple deep combinators found in sequence.\");return de(a.flatMap(r,o=>{let s=new Q(t,o);return s.run(),s.elements}))},fe=async function(t,e){for await(let r of $(t,e))return r;return null};var me=Object.freeze({...b,...A,...R,..._,...C,...k,...D,...E,Deferred:c,createFunction:W,createTextContent:d,IntervalPoller:T,isSuitableNodeForTextMatching:f,MutationPoller:y,RAFPoller:w}),he=me;\n";
8
+ export const source = "\"use strict\";var N=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var Y=Object.prototype.hasOwnProperty;var l=(t,e)=>{for(var r in e)N(t,r,{get:e[r],enumerable:!0})},G=(t,e,r,o)=>{if(e&&typeof e==\"object\"||typeof e==\"function\")for(let s of B(e))!Y.call(t,s)&&s!==r&&N(t,s,{get:()=>e[s],enumerable:!(o=X(e,s))||o.enumerable});return t};var J=t=>G(N({},\"__esModule\",{value:!0}),t);var pe={};l(pe,{default:()=>he});module.exports=J(pe);var x=class extends Error{constructor(e,r){super(e,r),this.name=this.constructor.name}get[Symbol.toStringTag](){return this.constructor.name}},p=class extends x{};var c=class t{static create(e){return new t(e)}static async race(e){let r=new Set;try{let o=e.map(s=>s instanceof t?(s.#s&&r.add(s),s.valueOrThrow()):s);return await Promise.race(o)}finally{for(let o of r)o.reject(new Error(\"Timeout cleared\"))}}#e=!1;#r=!1;#o;#t;#a=new Promise(e=>{this.#t=e});#s;#i;constructor(e){e&&e.timeout>0&&(this.#i=new p(e.message),this.#s=setTimeout(()=>{this.reject(this.#i)},e.timeout))}#l(e){clearTimeout(this.#s),this.#o=e,this.#t()}resolve(e){this.#r||this.#e||(this.#e=!0,this.#l(e))}reject(e){this.#r||this.#e||(this.#r=!0,this.#l(e))}resolved(){return this.#e}finished(){return this.#e||this.#r}value(){return this.#o}#n;valueOrThrow(){return this.#n||(this.#n=(async()=>{if(await this.#a,this.#r)throw this.#o;return this.#o})()),this.#n}};var L=new Map,W=t=>{let e=L.get(t);return e||(e=new Function(`return ${t}`)(),L.set(t,e),e)};var E={};l(E,{ariaQuerySelector:()=>z,ariaQuerySelectorAll:()=>b});var z=(t,e)=>globalThis.__ariaQuerySelector(t,e),b=async function*(t,e){yield*await globalThis.__ariaQuerySelectorAll(t,e)};var v={};l(v,{cssQuerySelector:()=>K,cssQuerySelectorAll:()=>Z});var K=(t,e)=>t.querySelector(e),Z=function(t,e){return t.querySelectorAll(e)};var A={};l(A,{CustomQuerySelectorRegistry:()=>y,customQuerySelectors:()=>P});var y=class{#e=new Map;register(e,r){if(!r.queryOne&&r.queryAll){let o=r.queryAll;r.queryOne=(s,i)=>{for(let n of o(s,i))return n;return null}}else if(r.queryOne&&!r.queryAll){let o=r.queryOne;r.queryAll=(s,i)=>{let n=o(s,i);return n?[n]:[]}}else if(!r.queryOne||!r.queryAll)throw new Error(\"At least one query method must be defined.\");this.#e.set(e,{querySelector:r.queryOne,querySelectorAll:r.queryAll})}unregister(e){this.#e.delete(e)}get(e){return this.#e.get(e)}clear(){this.#e.clear()}},P=new y;var R={};l(R,{pierceQuerySelector:()=>ee,pierceQuerySelectorAll:()=>te});var ee=(t,e)=>{let r=null,o=s=>{let i=document.createTreeWalker(s,NodeFilter.SHOW_ELEMENT);do{let n=i.currentNode;n.shadowRoot&&o(n.shadowRoot),!(n instanceof ShadowRoot)&&n!==s&&!r&&n.matches(e)&&(r=n)}while(!r&&i.nextNode())};return t instanceof Document&&(t=t.documentElement),o(t),r},te=(t,e)=>{let r=[],o=s=>{let i=document.createTreeWalker(s,NodeFilter.SHOW_ELEMENT);do{let n=i.currentNode;n.shadowRoot&&o(n.shadowRoot),!(n instanceof ShadowRoot)&&n!==s&&n.matches(e)&&r.push(n)}while(i.nextNode())};return t instanceof Document&&(t=t.documentElement),o(t),r};var u=(t,e)=>{if(!t)throw new Error(e)};var w=class{#e;#r;#o;#t;constructor(e,r){this.#e=e,this.#r=r}async start(){let e=this.#t=c.create(),r=await this.#e();if(r){e.resolve(r);return}this.#o=new MutationObserver(async()=>{let o=await this.#e();o&&(e.resolve(o),await this.stop())}),this.#o.observe(this.#r,{childList:!0,subtree:!0,attributes:!0})}async stop(){u(this.#t,\"Polling never started.\"),this.#t.finished()||this.#t.reject(new Error(\"Polling stopped\")),this.#o&&(this.#o.disconnect(),this.#o=void 0)}result(){return u(this.#t,\"Polling never started.\"),this.#t.valueOrThrow()}},T=class{#e;#r;constructor(e){this.#e=e}async start(){let e=this.#r=c.create(),r=await this.#e();if(r){e.resolve(r);return}let o=async()=>{if(e.finished())return;let s=await this.#e();if(!s){window.requestAnimationFrame(o);return}e.resolve(s),await this.stop()};window.requestAnimationFrame(o)}async stop(){u(this.#r,\"Polling never started.\"),this.#r.finished()||this.#r.reject(new Error(\"Polling stopped\"))}result(){return u(this.#r,\"Polling never started.\"),this.#r.valueOrThrow()}},S=class{#e;#r;#o;#t;constructor(e,r){this.#e=e,this.#r=r}async start(){let e=this.#t=c.create(),r=await this.#e();if(r){e.resolve(r);return}this.#o=setInterval(async()=>{let o=await this.#e();o&&(e.resolve(o),await this.stop())},this.#r)}async stop(){u(this.#t,\"Polling never started.\"),this.#t.finished()||this.#t.reject(new Error(\"Polling stopped\")),this.#o&&(clearInterval(this.#o),this.#o=void 0)}result(){return u(this.#t,\"Polling never started.\"),this.#t.valueOrThrow()}};var _={};l(_,{PCombinator:()=>H,pQuerySelector:()=>fe,pQuerySelectorAll:()=>$});var a=class{static async*map(e,r){for await(let o of e)yield await r(o)}static async*flatMap(e,r){for await(let o of e)yield*r(o)}static async collect(e){let r=[];for await(let o of e)r.push(o);return r}static async first(e){for await(let r of e)return r}};var C={};l(C,{textQuerySelectorAll:()=>m});var re=new Set([\"checkbox\",\"image\",\"radio\"]),oe=t=>t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement||t instanceof HTMLInputElement&&!re.has(t.type),se=new Set([\"SCRIPT\",\"STYLE\"]),f=t=>!se.has(t.nodeName)&&!document.head?.contains(t),I=new WeakMap,F=t=>{for(;t;)I.delete(t),t instanceof ShadowRoot?t=t.host:t=t.parentNode},j=new WeakSet,ne=new MutationObserver(t=>{for(let e of t)F(e.target)}),d=t=>{let e=I.get(t);if(e||(e={full:\"\",immediate:[]},!f(t)))return e;let r=\"\";if(oe(t))e.full=t.value,e.immediate.push(t.value),t.addEventListener(\"input\",o=>{F(o.target)},{once:!0,capture:!0});else{for(let o=t.firstChild;o;o=o.nextSibling){if(o.nodeType===Node.TEXT_NODE){e.full+=o.nodeValue??\"\",r+=o.nodeValue??\"\";continue}r&&e.immediate.push(r),r=\"\",o.nodeType===Node.ELEMENT_NODE&&(e.full+=d(o).full)}r&&e.immediate.push(r),t instanceof Element&&t.shadowRoot&&(e.full+=d(t.shadowRoot).full),j.has(t)||(ne.observe(t,{childList:!0,characterData:!0,subtree:!0}),j.add(t))}return I.set(t,e),e};var m=function*(t,e){let r=!1;for(let o of t.childNodes)if(o instanceof Element&&f(o)){let s;o.shadowRoot?s=m(o.shadowRoot,e):s=m(o,e);for(let i of s)yield i,r=!0}r||t instanceof Element&&f(t)&&d(t).full.includes(e)&&(yield t)};var k={};l(k,{checkVisibility:()=>le,pierce:()=>g,pierceAll:()=>O});var ie=[\"hidden\",\"collapse\"],le=(t,e)=>{if(!t)return e===!1;if(e===void 0)return t;let r=t.nodeType===Node.TEXT_NODE?t.parentElement:t,o=window.getComputedStyle(r),s=o&&!ie.includes(o.visibility)&&!ae(r);return e===s?t:!1};function ae(t){let e=t.getBoundingClientRect();return e.width===0||e.height===0}var ce=t=>\"shadowRoot\"in t&&t.shadowRoot instanceof ShadowRoot;function*g(t){ce(t)?yield t.shadowRoot:yield t}function*O(t){t=g(t).next().value,yield t;let e=[document.createTreeWalker(t,NodeFilter.SHOW_ELEMENT)];for(let r of e){let o;for(;o=r.nextNode();)o.shadowRoot&&(yield o.shadowRoot,e.push(document.createTreeWalker(o.shadowRoot,NodeFilter.SHOW_ELEMENT)))}}var D={};l(D,{xpathQuerySelectorAll:()=>q});var q=function*(t,e,r=-1){let s=(t.ownerDocument||document).evaluate(e,t,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE),i=[],n;for(;(n=s.iterateNext())&&(i.push(n),!(r&&i.length===r)););for(let h=0;h<i.length;h++)n=i[h],yield n,i[h]=null};var ue=/[-\\w\\P{ASCII}*]/u,H=(r=>(r.Descendent=\">>>\",r.Child=\">>>>\",r))(H||{}),V=t=>\"querySelectorAll\"in t,Q=class{#e;#r=[];#o=void 0;elements;constructor(e,r){this.elements=[e],this.#e=r,this.#t()}async run(){for(typeof this.#o==\"string\"&&this.#o.trimStart()===\":scope\"&&this.#t();this.#o!==void 0;this.#t()){let e=this.#o;typeof e==\"string\"?e[0]&&ue.test(e[0])?this.elements=a.flatMap(this.elements,async function*(r){V(r)&&(yield*r.querySelectorAll(e))}):this.elements=a.flatMap(this.elements,async function*(r){if(!r.parentElement){if(!V(r))return;yield*r.querySelectorAll(e);return}let o=0;for(let s of r.parentElement.children)if(++o,s===r)break;yield*r.parentElement.querySelectorAll(`:scope>:nth-child(${o})${e}`)}):this.elements=a.flatMap(this.elements,async function*(r){switch(e.name){case\"text\":yield*m(r,e.value);break;case\"xpath\":yield*q(r,e.value);break;case\"aria\":yield*b(r,e.value);break;default:let o=P.get(e.name);if(!o)throw new Error(`Unknown selector type: ${e.name}`);yield*o.querySelectorAll(r,e.value)}})}}#t(){if(this.#r.length!==0){this.#o=this.#r.shift();return}if(this.#e.length===0){this.#o=void 0;return}let e=this.#e.shift();switch(e){case\">>>>\":{this.elements=a.flatMap(this.elements,g),this.#t();break}case\">>>\":{this.elements=a.flatMap(this.elements,O),this.#t();break}default:this.#r=e,this.#t();break}}},M=class{#e=new WeakMap;calculate(e,r=[]){if(e===null)return r;e instanceof ShadowRoot&&(e=e.host);let o=this.#e.get(e);if(o)return[...o,...r];let s=0;for(let n=e.previousSibling;n;n=n.previousSibling)++s;let i=this.calculate(e.parentNode,[s]);return this.#e.set(e,i),[...i,...r]}},U=(t,e)=>{if(t.length+e.length===0)return 0;let[r=-1,...o]=t,[s=-1,...i]=e;return r===s?U(o,i):r<s?-1:1},de=async function*(t){let e=new Set;for await(let o of t)e.add(o);let r=new M;yield*[...e.values()].map(o=>[o,r.calculate(o)]).sort(([,o],[,s])=>U(o,s)).map(([o])=>o)},$=function(t,e){let r=JSON.parse(e);if(r.some(o=>{let s=0;return o.some(i=>(typeof i==\"string\"?++s:s=0,s>1))}))throw new Error(\"Multiple deep combinators found in sequence.\");return de(a.flatMap(r,o=>{let s=new Q(t,o);return s.run(),s.elements}))},fe=async function(t,e){for await(let r of $(t,e))return r;return null};var me=Object.freeze({...E,...A,...R,..._,...C,...k,...D,...v,Deferred:c,createFunction:W,createTextContent:d,IntervalPoller:S,isSuitableNodeForTextMatching:f,MutationPoller:w,RAFPoller:T}),he=me;\n";
@@ -17,8 +17,9 @@ export interface CustomQuerySelector {
17
17
 
18
18
  /**
19
19
  * This class mimics the injected {@link CustomQuerySelectorRegistry}.
20
+ *
20
21
  */
21
- class CustomQuerySelectorRegistry {
22
+ export class CustomQuerySelectorRegistry {
22
23
  #selectors = new Map<string, CustomQuerySelector>();
23
24
 
24
25
  register(name: string, handler: CustomQueryHandler): void {
@@ -54,7 +55,7 @@ class CustomQuerySelectorRegistry {
54
55
  return this.#selectors.get(name);
55
56
  }
56
57
 
57
- clear() {
58
+ clear(): void {
58
59
  this.#selectors.clear();
59
60
  }
60
61
  }
@@ -29,7 +29,7 @@ import type {ChromeReleaseChannel, LaunchOptions} from './LaunchOptions.js';
29
29
  * fetching and downloading browsers.
30
30
  *
31
31
  * If you're using Puppeteer in a Node environment, this is the class you'll get
32
- * when you run `require('puppeteer')` (or the equivalent ES `import`).
32
+ * when you run `import puppeteer from 'puppeteer'`.
33
33
  *
34
34
  * @remarks
35
35
  * The most common method to use is {@link PuppeteerNode.launch | launch}, which
@@ -8,7 +8,7 @@
8
8
  * @internal
9
9
  */
10
10
  export const PUPPETEER_REVISIONS = Object.freeze({
11
- chrome: '148.0.7778.167',
12
- 'chrome-headless-shell': '148.0.7778.167',
13
- firefox: 'stable_150.0.3',
11
+ chrome: '149.0.7827.22',
12
+ 'chrome-headless-shell': '149.0.7827.22',
13
+ firefox: 'stable_151.0',
14
14
  });
@@ -6,22 +6,27 @@
6
6
  import {Deferred} from './Deferred.js';
7
7
  import {disposeSymbol} from './disposable.js';
8
8
 
9
+ /**
10
+ * @internal
11
+ */
12
+ class MutexGuard {
13
+ #mutex: Mutex;
14
+ #onRelease?: () => void;
15
+ constructor(mutex: Mutex, onRelease?: () => void) {
16
+ this.#mutex = mutex;
17
+ this.#onRelease = onRelease;
18
+ }
19
+ [disposeSymbol](): void {
20
+ this.#onRelease?.();
21
+ return this.#mutex.release();
22
+ }
23
+ }
24
+
9
25
  /**
10
26
  * @internal
11
27
  */
12
28
  export class Mutex {
13
- static Guard = class Guard {
14
- #mutex: Mutex;
15
- #onRelease?: () => void;
16
- constructor(mutex: Mutex, onRelease?: () => void) {
17
- this.#mutex = mutex;
18
- this.#onRelease = onRelease;
19
- }
20
- [disposeSymbol](): void {
21
- this.#onRelease?.();
22
- return this.#mutex.release();
23
- }
24
- };
29
+ static Guard = MutexGuard;
25
30
 
26
31
  #locked = false;
27
32
  #acquirers: Array<() => void> = [];
@@ -6,5 +6,5 @@
6
6
 
7
7
  // If moved update release-please config
8
8
  // x-release-please-start-version
9
- export const packageVersion = '25.0.4';
9
+ export const packageVersion = '25.1.0';
10
10
  // x-release-please-end
@@ -2,6 +2,8 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
+ import * as Greendev from '../../../models/greendev/greendev.js';
6
+
5
7
  /**
6
8
  * To use links in markdown, add key here with the link and
7
9
  * use the added key in markdown.
@@ -106,6 +108,11 @@ export const getMarkdownLink = (key: string): string => {
106
108
  }
107
109
  const link = markdownLinks.get(key);
108
110
  if (!link) {
111
+ if (Greendev.Prototypes.instance().isEnabled('beyondStylingAntigravity') ||
112
+ Greendev.Prototypes.instance().isEnabled('beyondStylingGemini')) {
113
+ return key;
114
+ }
115
+
109
116
  throw new Error(`Markdown link with key '${key}' is not available, please check MarkdownLinksMap.ts`);
110
117
  }
111
118
  return link;
@@ -130,7 +130,8 @@ export class InspectorDrawerView {
130
130
  this.#drawerMinimizedSetting =
131
131
  Common.Settings.Settings.instance().createLocalSetting('inspector.drawer-minimized', false);
132
132
  this.tabbedLocation = ViewManager.instance().createTabbedLocation(
133
- options.revealDrawer, 'drawer-view', true, true, undefined, options.isVisible, () => new DrawerTabbedPane());
133
+ options.revealDrawer, 'drawer-view', true, true,
134
+ {isLocationVisible: options.isVisible, tabbedPaneFactory: () => new DrawerTabbedPane()});
134
135
  this.#moreTabsButton = this.tabbedLocation.enableMoreTabsButton();
135
136
  this.#moreTabsButton.setTitle(i18nString(UIStrings.moreTools));
136
137
  this.tabbedPane = this.tabbedLocation.tabbedPane() as DrawerTabbedPane;
@@ -228,7 +228,7 @@ export class InspectorView extends VBox implements ViewLocationResolver {
228
228
  this.tabbedLocation = ViewManager.instance().createTabbedLocation(
229
229
  Host.InspectorFrontendHost.InspectorFrontendHostInstance.bringToFront.bind(
230
230
  Host.InspectorFrontendHost.InspectorFrontendHostInstance),
231
- 'panel', true, true, Root.Runtime.Runtime.queryParam('panel'));
231
+ 'panel', true, true, {defaultTab: Root.Runtime.Runtime.queryParam('panel')});
232
232
 
233
233
  this.tabbedPane = this.tabbedLocation.tabbedPane();
234
234
  this.tabbedPane.setMinimumSize(MIN_MAIN_PANEL_WIDTH, 0);
@@ -0,0 +1,269 @@
1
+ // Copyright 2026 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ // Side-effect import: registers the `<devtools-menu-button>` custom element
6
+ // used by `PLUS_BUTTON_VIEW` below. The named imports are type-only.
7
+ import './ContextMenu.js';
8
+
9
+ import * as Host from '../../core/host/host.js';
10
+ import * as i18n from '../../core/i18n/i18n.js';
11
+ import type * as Platform from '../../core/platform/platform.js';
12
+ import {Directives, html, render} from '../lit/lit.js';
13
+
14
+ import type {ContextMenu, MenuButton} from './ContextMenu.js';
15
+ import type {View} from './View.js';
16
+ import {ViewLocationValues} from './ViewRegistration.js';
17
+
18
+ const UIStrings = {
19
+ /**
20
+ * @description Default tooltip / accessible name of the "plus" button shown
21
+ * after the visible tabs in a tab strip. Clicking it opens a menu listing
22
+ * tools that are not currently shown as a visible tab.
23
+ */
24
+ moreTools: 'More tools',
25
+ } as const;
26
+ const str_ = i18n.i18n.registerUIStrings('ui/legacy/PlusButton.ts', UIStrings);
27
+ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
28
+
29
+ /** Declarative configuration for the plus button. */
30
+ export interface PlusButtonOptions {
31
+ title?: Platform.UIString.LocalizedString;
32
+ jslogContext?: string;
33
+ }
34
+
35
+ /**
36
+ * Minimal `TabbedPane` surface read by the populator. Defined as an
37
+ * interface so test doubles can satisfy it without an `as unknown as
38
+ * TabbedPane` double-cast.
39
+ */
40
+ export interface PlusButtonTabbedPane {
41
+ element: HTMLElement;
42
+ hiddenTabs(): ReadonlyArray<{id: string, title: string, jslogContext?: string}>;
43
+ hasTab(id: string): boolean;
44
+ firstHiddenTabIndex(): number;
45
+ moveTab(tabId: string, newIndex: number): void;
46
+ selectTab(tabId: string, userGesture?: boolean, forceFocus?: boolean): boolean;
47
+ }
48
+
49
+ export interface PlusButtonMenuContext {
50
+ tabbedPane: PlusButtonTabbedPane;
51
+ location: string;
52
+ /**
53
+ * Production callers pass `() => location.views.values()` (NOT
54
+ * `manager.viewsForLocation(location)`) so views moved in via
55
+ * `appendView` are reflected immediately. Called fresh on every
56
+ * menu open.
57
+ */
58
+ views: () => Iterable<View>;
59
+ manager: {
60
+ viewsForLocation(location: string): View[],
61
+ moveView(viewId: string, locationName: string): void,
62
+ };
63
+ showView: (view: View) => void;
64
+ }
65
+
66
+ interface AddToolEntry {
67
+ title: string;
68
+ jslogContext: string;
69
+ isPreviewFeature: boolean;
70
+ action: () => void;
71
+ }
72
+
73
+ export interface OverflowTabModel {
74
+ id: string;
75
+ title: string;
76
+ jslogContext?: string;
77
+ }
78
+
79
+ export interface PlusButtonMenuModel {
80
+ overflowTabs: readonly OverflowTabModel[];
81
+ addToolEntries: readonly AddToolEntry[];
82
+ }
83
+
84
+ /**
85
+ * Presenter (MVP) for the plus-button menu. {@link buildModel} is called
86
+ * fresh on every menu open so newly-registered views — or views that
87
+ * just left the visible tab strip — are reflected immediately.
88
+ */
89
+ export class PlusButtonPresenter {
90
+ readonly #context: PlusButtonMenuContext;
91
+
92
+ constructor(context: PlusButtonMenuContext) {
93
+ this.#context = context;
94
+ }
95
+
96
+ buildModel(): PlusButtonMenuModel {
97
+ const {tabbedPane, location, views, manager} = this.#context;
98
+ const overflowTabs: readonly OverflowTabModel[] =
99
+ tabbedPane.hiddenTabs().map(tab => ({id: tab.id, title: tab.title, jslogContext: tab.jslogContext}));
100
+
101
+ const addToolEntries: AddToolEntry[] = [];
102
+ // Seed dedup sets from the overflowed tabs so an addable entry
103
+ // (e.g. a closeable view in the other main location) sharing an id
104
+ // or title with an overflowed tab is not listed twice.
105
+ const seenIds = new Set<string>(overflowTabs.map(tab => tab.id));
106
+ const seenTitles = new Set<string>(overflowTabs.map(tab => tab.title));
107
+
108
+ for (const view of views()) {
109
+ // Skip views that already have a tab. Hidden tabs are already listed
110
+ // in the overflow section above, and visible tabs are accessible
111
+ // directly in the tab strip.
112
+ if (tabbedPane.hasTab(view.viewId())) {
113
+ continue;
114
+ }
115
+ // Transient views are not user-addable.
116
+ if (view.isTransient()) {
117
+ continue;
118
+ }
119
+ if (seenIds.has(view.viewId()) || seenTitles.has(view.title())) {
120
+ continue;
121
+ }
122
+ seenIds.add(view.viewId());
123
+ seenTitles.add(view.title());
124
+ const isIssuesPane = view.viewId() === 'issues-pane';
125
+ addToolEntries.push({
126
+ title: view.title(),
127
+ jslogContext: view.viewId(),
128
+ isPreviewFeature: view.isPreviewFeature(),
129
+ action: () => {
130
+ if (isIssuesPane) {
131
+ // Distinct from `HAMBURGER_MENU` so plus-button opens are
132
+ // not conflated with three-dot-menu opens in the dashboard.
133
+ Host.userMetrics.issuesPanelOpenedFrom(Host.UserMetrics.IssueOpener.MORE_TOOLS_MENU);
134
+ }
135
+ this.#context.showView(view);
136
+ },
137
+ });
138
+ }
139
+
140
+ // Offer cross-location moves between the two main surfaces: the
141
+ // panel plus button lists drawer views and vice versa.
142
+ const otherLocation = location === ViewLocationValues.PANEL ? ViewLocationValues.DRAWER_VIEW :
143
+ location === ViewLocationValues.DRAWER_VIEW ? ViewLocationValues.PANEL :
144
+ null;
145
+ if (otherLocation) {
146
+ for (const view of manager.viewsForLocation(otherLocation)) {
147
+ // Non-closeable views (e.g. Console) cannot be moved between
148
+ // locations, so they're excluded here. They still appear in the
149
+ // overflow section when their own location's tab strip overflows.
150
+ if (view.isTransient() || !view.isCloseable() || seenIds.has(view.viewId()) || seenTitles.has(view.title())) {
151
+ continue;
152
+ }
153
+ seenIds.add(view.viewId());
154
+ seenTitles.add(view.title());
155
+ const viewId = view.viewId();
156
+ addToolEntries.push({
157
+ title: view.title(),
158
+ jslogContext: viewId,
159
+ isPreviewFeature: view.isPreviewFeature(),
160
+ action: () => manager.moveView(viewId, location),
161
+ });
162
+ }
163
+ }
164
+
165
+ addToolEntries.sort((a, b) => a.title.localeCompare(b.title));
166
+
167
+ return {overflowTabs, addToolEntries};
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Renders the plus-button menu by asking {@link PlusButtonPresenter}
173
+ * for a model and pushing it into `contextMenu`. Overflowed tabs (in
174
+ * tab order) come first, followed by deduplicated "add tool" entries
175
+ * sorted alphabetically.
176
+ */
177
+ export function populatePlusButtonMenu(contextMenu: ContextMenu, context: PlusButtonMenuContext): void {
178
+ const model = new PlusButtonPresenter(context).buildModel();
179
+ const hasOverflow = model.overflowTabs.length > 0;
180
+
181
+ // When there are no overflowed tabs, surface the add-tool entries in
182
+ // the default section so they are not visually demoted to a footer.
183
+ for (const tab of model.overflowTabs) {
184
+ contextMenu.defaultSection().appendItem(
185
+ tab.title, () => revealOverflowTab(context.tabbedPane, tab.id), {jslogContext: tab.jslogContext ?? tab.id});
186
+ }
187
+ const addToolSection = hasOverflow ? contextMenu.footerSection() : contextMenu.defaultSection();
188
+ for (const entry of model.addToolEntries) {
189
+ addToolSection.appendItem(
190
+ entry.title, entry.action, {isPreviewFeature: entry.isPreviewFeature, jslogContext: entry.jslogContext});
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Reveals an overflowed tab and persists its new position via
196
+ * `moveTab(firstHidden - 1)` so the tab stays in the visible region
197
+ * after a reload — independent of any runtime `currentTab` /
198
+ * `lastSelectedOverflowTab` priority logic. The previously-last-visible
199
+ * tab is pushed to the start of the overflow region, matching the
200
+ * intuition that the newly opened tab replaces the one the user
201
+ * implicitly stopped using.
202
+ *
203
+ * Exported only for testing.
204
+ */
205
+ export function revealOverflowTab(tabbedPane: PlusButtonTabbedPane, tabId: string): void {
206
+ const firstHidden = tabbedPane.firstHiddenTabIndex();
207
+ if (firstHidden > 0) {
208
+ // `firstHidden - 1` is the index of the last currently-visible tab.
209
+ tabbedPane.moveTab(tabId, firstHidden - 1);
210
+ }
211
+ tabbedPane.selectTab(tabId, /* userGesture */ true, /* forceFocus */ true);
212
+ }
213
+
214
+ interface PlusButtonViewInput {
215
+ title: string;
216
+ jslogContext: string;
217
+ populateMenuCall: (menu: ContextMenu) => void;
218
+ }
219
+
220
+ /**
221
+ * Standard `(input, output, target)` view function so `Lit.render` is
222
+ * called inside a view (per `@devtools/no-lit-render-outside-of-view`).
223
+ * `output.button` is captured via `ref` to avoid a `querySelector`
224
+ * round-trip in {@link installPlusButton}.
225
+ *
226
+ * `slot` is set declaratively in the template so the attribute is
227
+ * present on the very first connection — the first `slotchange` then
228
+ * sees the button as the trailing-slot target and no extra layout pass
229
+ * is needed.
230
+ */
231
+ export const PLUS_BUTTON_VIEW =
232
+ (input: PlusButtonViewInput, output: {button?: MenuButton}, target: HTMLElement): void => {
233
+ render(
234
+ html`
235
+ <devtools-menu-button
236
+ ${Directives.ref(el => {
237
+ output.button = el as MenuButton | undefined;
238
+ })}
239
+ slot="trailing-button"
240
+ .iconName=${'plus'}
241
+ .title=${input.title}
242
+ .jslogContext=${input.jslogContext}
243
+ .populateMenuCall=${input.populateMenuCall}>
244
+ </devtools-menu-button>`,
245
+ target);
246
+ };
247
+
248
+ /**
249
+ * Renders a `<devtools-menu-button>` configured as the plus button into
250
+ * `tabbedPane`'s `trailing-button` slot and returns the slotted host.
251
+ * The returned `MenuButton` is used by the next CL to toggle visibility
252
+ * (e.g. when the drawer is minimized).
253
+ */
254
+ export function installPlusButton(context: PlusButtonMenuContext, options: PlusButtonOptions = {}): MenuButton {
255
+ const output: {button?: MenuButton} = {};
256
+ // `render` is synchronous and the `ref` directive fires during render,
257
+ // so `output.button` is assigned by the time the view returns.
258
+ PLUS_BUTTON_VIEW(
259
+ {
260
+ title: options.title ?? i18nString(UIStrings.moreTools),
261
+ jslogContext: options.jslogContext ?? '',
262
+ populateMenuCall: menu => populatePlusButtonMenu(menu, context),
263
+ },
264
+ output, context.tabbedPane.element);
265
+ if (!output.button) {
266
+ throw new Error('installPlusButton: ref directive did not capture <devtools-menu-button>');
267
+ }
268
+ return output.button;
269
+ }