chrome-devtools-frontend 1.0.1555430 → 1.0.1558690

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 (232) hide show
  1. package/front_end/core/common/Object.ts +5 -1
  2. package/front_end/core/host/ResourceLoader.ts +1 -1
  3. package/front_end/core/host/UserMetrics.ts +3 -1
  4. package/front_end/core/sdk/DOMModel.ts +7 -0
  5. package/front_end/core/sdk/NetworkManager.ts +0 -7
  6. package/front_end/core/sdk/SourceMap.ts +16 -2
  7. package/front_end/core/sdk/SourceMapManager.ts +1 -1
  8. package/front_end/core/sdk/SourceMapScopesInfo.ts +11 -4
  9. package/front_end/entrypoints/formatter_worker/FormatterActions.ts +3 -0
  10. package/front_end/entrypoints/formatter_worker/ScopeParser.ts +119 -8
  11. package/front_end/entrypoints/formatter_worker/Substitute.ts +1 -1
  12. package/front_end/entrypoints/main/GlobalAiButton.ts +5 -1
  13. package/front_end/generated/Deprecation.ts +0 -7
  14. package/front_end/generated/InspectorBackendCommands.ts +4 -4
  15. package/front_end/generated/protocol.ts +9 -1
  16. package/front_end/models/ai_assistance/AiConversation.ts +71 -10
  17. package/front_end/models/ai_assistance/ArtifactsManager.ts +67 -0
  18. package/front_end/models/ai_assistance/ConversationHandler.ts +3 -2
  19. package/front_end/models/ai_assistance/agents/AiAgent.ts +17 -27
  20. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +151 -3
  21. package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
  22. package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
  23. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +0 -2
  24. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +3 -3
  25. package/front_end/models/annotations/AnnotationRepository.ts +2 -2
  26. package/front_end/models/bindings/CompilerScriptMapping.ts +7 -6
  27. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +4 -4
  28. package/front_end/models/greendev/Prototypes.ts +56 -0
  29. package/front_end/models/greendev/README.md +5 -0
  30. package/front_end/models/greendev/greendev.ts +5 -0
  31. package/front_end/models/javascript_metadata/NativeFunctions.js +2 -2
  32. package/front_end/models/stack_trace/StackTraceImpl.ts +5 -3
  33. package/front_end/models/stack_trace/StackTraceModel.ts +53 -40
  34. package/front_end/models/trace/EventsSerializer.ts +8 -2
  35. package/front_end/models/trace/extras/TraceTree.ts +4 -2
  36. package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +2 -2
  37. package/front_end/models/trace/insights/LCPDiscovery.ts +0 -2
  38. package/front_end/models/trace/types/TraceEvents.ts +0 -1
  39. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +96 -91
  40. package/front_end/panels/ai_assistance/aiAssistancePanel.css +16 -0
  41. package/front_end/panels/ai_assistance/components/ArtifactsViewer.ts +109 -7
  42. package/front_end/panels/ai_assistance/components/ChatView.ts +2 -2
  43. package/front_end/panels/ai_assistance/components/CollapsibleAssistanceContentWidget.ts +7 -8
  44. package/front_end/panels/ai_assistance/components/PerformanceAgentFlameChart.ts +15 -8
  45. package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +9 -9
  46. package/front_end/panels/ai_assistance/components/artifactsViewer.css +6 -1
  47. package/front_end/panels/ai_assistance/components/collapsibleAssistanceContentWidget.css +5 -6
  48. package/front_end/panels/application/AppManifestView.ts +360 -391
  49. package/front_end/panels/application/ApplicationPanelSidebar.ts +24 -57
  50. package/front_end/panels/application/CookieItemsView.ts +1 -0
  51. package/front_end/panels/application/OpenedWindowDetailsView.ts +2 -0
  52. package/front_end/panels/application/ServiceWorkersView.ts +2 -0
  53. package/front_end/panels/application/SharedStorageTreeElement.ts +3 -0
  54. package/front_end/panels/application/StorageView.ts +1 -0
  55. package/front_end/panels/application/appManifestView.css +49 -1
  56. package/front_end/panels/application/components/ProtocolHandlersView.ts +2 -2
  57. package/front_end/panels/console/ConsoleViewMessage.ts +4 -3
  58. package/front_end/panels/elements/ElementsTreeElement.ts +30 -1
  59. package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
  60. package/front_end/panels/elements/ElementsTreeOutlineRenderer.ts +7 -1
  61. package/front_end/panels/elements/components/AdornerManager.ts +8 -0
  62. package/front_end/panels/emulation/DeviceModeToolbar.ts +3 -1
  63. package/front_end/panels/issues/AffectedResourcesView.ts +0 -1
  64. package/front_end/panels/lighthouse/LighthousePanel.ts +10 -0
  65. package/front_end/panels/lighthouse/lighthousePanel.css +46 -3
  66. package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +4 -8
  67. package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +148 -97
  68. package/front_end/panels/linear_memory_inspector/components/LinearMemoryViewer.ts +1 -1
  69. package/front_end/panels/linear_memory_inspector/components/linearMemoryValueInterpreter.css +37 -35
  70. package/front_end/panels/network/NetworkLogViewColumns.ts +9 -9
  71. package/front_end/panels/network/RequestCookiesView.ts +125 -141
  72. package/front_end/panels/network/components/RequestHeadersView.ts +2 -2
  73. package/front_end/panels/network/requestCookiesView.css +22 -20
  74. package/front_end/panels/recorder/components/RecordingView.ts +3 -3
  75. package/front_end/panels/recorder/components/StepView.ts +2 -1
  76. package/front_end/panels/settings/SettingsScreen.ts +133 -1
  77. package/front_end/panels/settings/keybindsSettingsTab.css +4 -0
  78. package/front_end/panels/settings/settings-meta.ts +24 -0
  79. package/front_end/panels/settings/settingsScreen.css +4 -0
  80. package/front_end/panels/sources/CallStackSidebarPane.ts +7 -3
  81. package/front_end/panels/sources/DebuggerPausedMessage.ts +125 -90
  82. package/front_end/panels/sources/SourcesPanel.ts +10 -7
  83. package/front_end/panels/sources/UISourceCodeFrame.ts +3 -17
  84. package/front_end/panels/sources/debuggerPausedMessage.css +8 -0
  85. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -1
  86. package/front_end/panels/timeline/components/sidebarInsightsTab.css +2 -0
  87. package/front_end/third_party/acorn/estree-legacy.d.ts +4 -0
  88. package/front_end/third_party/chromium/README.chromium +1 -1
  89. package/front_end/third_party/puppeteer/README.chromium +2 -2
  90. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts +12 -0
  91. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts.map +1 -1
  92. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.js.map +1 -1
  93. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/CDPSession.d.ts.map +1 -1
  94. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/CDPSession.js.map +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/ElementHandle.d.ts.map +1 -1
  96. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/ElementHandle.js.map +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Frame.d.ts.map +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Frame.js.map +1 -1
  99. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +14 -2
  100. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
  101. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.d.ts +3 -1
  103. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.d.ts.map +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.js +6 -0
  105. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.js.map +1 -1
  106. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.d.ts +0 -1
  107. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
  108. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js +0 -20
  109. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js.map +1 -1
  110. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts +3 -1
  111. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts.map +1 -1
  112. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js +10 -14
  113. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js.map +1 -1
  114. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.d.ts +1 -0
  115. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
  116. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js +14 -0
  117. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
  118. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Connection.d.ts.map +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts +3 -1
  120. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +12 -0
  122. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
  123. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/EmulationManager.d.ts +1 -0
  124. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/EmulationManager.d.ts.map +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/EmulationManager.js +22 -0
  126. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/EmulationManager.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts +3 -1
  128. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts.map +1 -1
  129. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +9 -2
  130. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
  131. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/BrowserConnector.js +21 -7
  132. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/BrowserConnector.js.map +1 -1
  133. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/EventEmitter.d.ts.map +1 -1
  134. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  135. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
  136. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
  137. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  138. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  139. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  140. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  141. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +26 -0
  142. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +86 -20
  143. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts +12 -0
  144. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts.map +1 -1
  145. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.js.map +1 -1
  146. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/CDPSession.d.ts.map +1 -1
  147. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/CDPSession.js.map +1 -1
  148. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/ElementHandle.d.ts.map +1 -1
  149. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/ElementHandle.js.map +1 -1
  150. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Frame.d.ts.map +1 -1
  151. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Frame.js.map +1 -1
  152. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +14 -2
  153. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
  154. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
  155. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.d.ts +3 -1
  156. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.d.ts.map +1 -1
  157. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.js +6 -0
  158. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.js.map +1 -1
  159. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.d.ts +0 -1
  160. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
  161. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js +0 -20
  162. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js.map +1 -1
  163. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts +3 -1
  164. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts.map +1 -1
  165. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js +11 -15
  166. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js.map +1 -1
  167. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.d.ts +1 -0
  168. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
  169. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js +14 -0
  170. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
  171. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Connection.d.ts.map +1 -1
  172. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts +3 -1
  173. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
  174. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +12 -0
  175. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
  176. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/EmulationManager.d.ts +1 -0
  177. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/EmulationManager.d.ts.map +1 -1
  178. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/EmulationManager.js +22 -0
  179. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/EmulationManager.js.map +1 -1
  180. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts +3 -1
  181. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts.map +1 -1
  182. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +9 -2
  183. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
  184. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/BrowserConnector.js +21 -7
  185. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/BrowserConnector.js.map +1 -1
  186. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/EventEmitter.d.ts.map +1 -1
  187. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
  188. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
  189. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  190. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  191. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  192. package/front_end/third_party/puppeteer/package/lib/types.d.ts +26 -0
  193. package/front_end/third_party/puppeteer/package/package.json +2 -2
  194. package/front_end/third_party/puppeteer/package/src/api/Browser.ts +18 -0
  195. package/front_end/third_party/puppeteer/package/src/api/CDPSession.ts +1 -2
  196. package/front_end/third_party/puppeteer/package/src/api/ElementHandle.ts +2 -4
  197. package/front_end/third_party/puppeteer/package/src/api/Frame.ts +2 -4
  198. package/front_end/third_party/puppeteer/package/src/api/Page.ts +18 -6
  199. package/front_end/third_party/puppeteer/package/src/bidi/Browser.ts +13 -0
  200. package/front_end/third_party/puppeteer/package/src/bidi/HTTPRequest.ts +0 -33
  201. package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +14 -28
  202. package/front_end/third_party/puppeteer/package/src/bidi/core/BrowsingContext.ts +19 -0
  203. package/front_end/third_party/puppeteer/package/src/bidi/core/Connection.ts +3 -2
  204. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +19 -0
  205. package/front_end/third_party/puppeteer/package/src/cdp/EmulationManager.ts +30 -0
  206. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +15 -6
  207. package/front_end/third_party/puppeteer/package/src/common/BrowserConnector.ts +29 -10
  208. package/front_end/third_party/puppeteer/package/src/common/EventEmitter.ts +3 -3
  209. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  210. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  211. package/front_end/ui/components/icon_button/iconButton.css +3 -1
  212. package/front_end/ui/components/report_view/ReportView.docs.ts +37 -0
  213. package/front_end/ui/components/report_view/ReportView.ts +12 -6
  214. package/front_end/ui/components/report_view/report.css +16 -0
  215. package/front_end/ui/components/settings/SettingCheckbox.ts +1 -1
  216. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +135 -7
  217. package/front_end/ui/components/text_editor/config.ts +6 -6
  218. package/front_end/ui/legacy/ContextMenu.ts +11 -2
  219. package/front_end/ui/legacy/Floaty.ts +5 -9
  220. package/front_end/ui/legacy/InspectorView.ts +2 -1
  221. package/front_end/ui/legacy/ReportView.ts +5 -4
  222. package/front_end/ui/legacy/TextPrompt.ts +1 -1
  223. package/front_end/ui/legacy/Toolbar.ts +4 -0
  224. package/front_end/ui/legacy/UIUtils.ts +0 -2
  225. package/front_end/ui/legacy/Widget.ts +7 -0
  226. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +18 -3
  227. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +3 -3
  228. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +6 -0
  229. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +0 -1
  230. package/front_end/ui/legacy/reportView.css +0 -24
  231. package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
  232. package/package.json +1 -1
@@ -1,10 +1,9 @@
1
1
  // Copyright 2016 The Chromium Authors
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
- /* eslint-disable @devtools/no-imperative-dom-api, @devtools/no-lit-render-outside-of-view */
5
4
 
6
- import '../../ui/kit/kit.js';
7
5
  import '../../ui/legacy/components/inline_editor/inline_editor.js';
6
+ import '../../ui/components/report_view/report_view.js';
8
7
 
9
8
  import * as Common from '../../core/common/common.js';
10
9
  import * as Host from '../../core/host/host.js';
@@ -15,12 +14,16 @@ import type * as Protocol from '../../generated/protocol.js';
15
14
  import * as Buttons from '../../ui/components/buttons/buttons.js';
16
15
  import * as Components from '../../ui/legacy/components/utils/utils.js';
17
16
  import * as UI from '../../ui/legacy/legacy.js';
18
- import {html, i18nTemplate, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
17
+ import {Directives, html, i18nTemplate, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
19
18
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
20
19
 
21
20
  import appManifestViewStyles from './appManifestView.css.js';
22
21
  import * as ApplicationComponents from './components/components.js';
23
22
 
23
+ const {styleMap, classMap, ref} = Directives;
24
+ const {linkifyURL} = Components.Linkifier.Linkifier;
25
+ const {widgetConfig} = UI.Widget;
26
+
24
27
  const UIStrings = {
25
28
  /**
26
29
  * @description Text in App Manifest View of the Application panel
@@ -446,6 +449,11 @@ const UIStrings = {
446
449
  * @description Text for emulation OS selection dropdown
447
450
  */
448
451
  selectWindowControlsOverlayEmulationOs: 'Emulate the Window Controls Overlay on',
452
+ /**
453
+ * @description Alert message for screen reader to announce which subsection is being scrolled to
454
+ * @example {"Identity"} PH1
455
+ */
456
+ onInvokeAlert: 'Scrolled to {PH1}',
449
457
  } as const;
450
458
  const str_ = i18n.i18n.registerUIStrings('panels/application/AppManifestView.ts', UIStrings);
451
459
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -506,13 +514,6 @@ interface Manifest {
506
514
  }
507
515
  /* eslint-enable @typescript-eslint/naming-convention */
508
516
 
509
- interface ReportSectionItem {
510
- content: LitTemplate|LitTemplate[]|string|HTMLElement;
511
- title?: string;
512
- label?: string;
513
- flexed?: boolean;
514
- }
515
-
516
517
  interface IdentitySectionData {
517
518
  name: string;
518
519
  shortName: string;
@@ -592,76 +593,80 @@ type ProcessedImageResource = {
592
593
  imageSrc: string,
593
594
  };
594
595
 
595
- function renderErrors(
596
- errorsSection: UI.ReportView.Section, warnings?: Platform.UIString.LocalizedString[],
597
- manifestErrors?: Protocol.Page.AppManifestError[], imageErrors?: Platform.UIString.LocalizedString[]): void {
598
- errorsSection.clearContent();
599
- errorsSection.element.classList.toggle(
600
- 'hidden', !manifestErrors?.length && !warnings?.length && !imageErrors?.length);
601
-
602
- for (const error of manifestErrors ?? []) {
603
- const icon = UI.UIUtils.createIconLabel({
604
- title: error.message,
605
- iconName: error.critical ? 'cross-circle-filled' : 'warning-filled',
606
- color: error.critical ? 'var(--icon-error)' : 'var(--icon-warning)',
607
- });
608
- errorsSection.appendRow().appendChild(icon);
609
- }
596
+ function renderSectionHeader(text: Platform.UIString.LocalizedString, output?: ViewOutput): LitTemplate {
597
+ // clang-format off
598
+ return html`
599
+ <devtools-report-section-header
600
+ ${ref(e => { if (output && e instanceof HTMLElement) {
601
+ output.scrollToSection.set(text, () => { e.scrollIntoView(); });
602
+ }})}>
603
+ ${text}
604
+ </devtools-report-section-header>`;
605
+ // clang-format on
606
+ }
610
607
 
611
- for (const warning of warnings ?? []) {
612
- const msgElement = document.createTextNode(warning);
613
- errorsSection.appendRow().appendChild(msgElement);
614
- }
615
- for (const error of imageErrors ?? []) {
616
- const msgElement = document.createTextNode(error);
617
- errorsSection.appendRow().appendChild(msgElement);
618
- }
608
+ function renderErrors(
609
+ warnings?: Platform.UIString.LocalizedString[], manifestErrors?: Protocol.Page.AppManifestError[],
610
+ imageErrors?: Platform.UIString.LocalizedString[], output?: ViewOutput): LitTemplate {
611
+ // clang-format off
612
+ return html`
613
+ ${renderSectionHeader(i18nString(UIStrings.errorsAndWarnings), output)}
614
+ <div class="report-section" jslog=${VisualLogging.section('errors-and-warnings')}>
615
+ ${manifestErrors?.map(error => html`<div class="report-row">
616
+ <devtools-icon
617
+ name=${error.critical ? 'cross-circle-filled' : 'warning-filled'}
618
+ style=${styleMap({color: error.critical ? 'var(--icon-error)' : 'var(--icon-warning)'})}>
619
+ </devtools-icon>
620
+ ${error.message}</div>
621
+ `)}
622
+ ${warnings?.map(warning => html`<div class="report-row">${warning}</div>`)}
623
+ ${imageErrors?.map(error => html`<div class="report-row">${error}</div>`)}
624
+ </div>`;
625
+ // clang-format on
619
626
  }
620
627
 
621
- function renderIdentity(identitySection: UI.ReportView.Section, identityData: IdentitySectionData): void {
628
+ function renderIdentity(identityData: IdentitySectionData, onCopy: () => void, output: ViewOutput): LitTemplate {
622
629
  const {name, shortName, description, appId, recommendedId, hasId} = identityData;
623
- const fields: ReportSectionItem[] = [];
624
- fields.push({title: i18nString(UIStrings.name), content: name});
625
- fields.push({title: i18nString(UIStrings.shortName), content: shortName});
626
- fields.push({title: i18nString(UIStrings.description), content: description});
627
-
628
- if (appId && recommendedId) {
629
- const onCopy = (): void => {
630
- UI.ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.copiedToClipboard, {PH1: recommendedId}));
631
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(recommendedId);
632
- };
633
- // clang-format off
634
- fields.push({title: i18nString(UIStrings.computedAppId), label: 'App Id', content: html`
635
- ${appId}
636
- <devtools-icon class="inline-icon" name="help" title=${i18nString(UIStrings.appIdExplainer)}
637
- jslog=${VisualLogging.action('help').track({hover: true})}>
638
- </devtools-icon>
639
- <devtools-link href="https://developer.chrome.com/blog/pwa-manifest-id/"
640
- .jslogContext=${'learn-more'}>
641
- ${i18nString(UIStrings.learnMore)}
642
- </devtools-link>
643
- ${!hasId ? html`
644
- <div class="multiline-value">
645
- ${i18nTemplate(str_, UIStrings.appIdNote, {
646
- PH1: html`<code>${recommendedId}</code>`,
647
- PH2: html`<devtools-button class="inline-button" @click=${onCopy}
648
- .iconName=${'copy'}
649
- .variant=${Buttons.Button.Variant.ICON}
650
- .size=${Buttons.Button.Size.SMALL}
651
- .jslogContext=${'manifest.copy-id'}
652
- .title=${i18nString(UIStrings.copyToClipboard)}>
653
- </devtools-button>`,
654
- })}
655
- </div>` : nothing}`});
656
- // clang-format on
657
- } else {
658
- identitySection.removeField(i18nString(UIStrings.computedAppId));
659
- }
660
- setSectionContents(fields, identitySection);
630
+ // clang-format off
631
+ return html`${renderSectionHeader(i18nString(UIStrings.identity), output)}
632
+ <div class="report-section" jslog=${VisualLogging.section('identity')}>
633
+ <devtools-report-key>${i18nString(UIStrings.name)}</devtools-report-key>
634
+ <devtools-report-value>${name}</devtools-report-value>
635
+ <devtools-report-key>${i18nString(UIStrings.shortName)}</devtools-report-key>
636
+ <devtools-report-value>${shortName}</devtools-report-value>
637
+ <devtools-report-key>${i18nString(UIStrings.description)}</devtools-report-key>
638
+ <devtools-report-value>${description}</devtools-report-value>
639
+ ${appId && recommendedId ? html`
640
+ <devtools-report-key aria-label="App Id">${i18nString(UIStrings.computedAppId)}</devtools-report-key>
641
+ <devtools-report-value jslog=${VisualLogging.section('identity')}>
642
+ ${appId}
643
+ <devtools-icon class="inline-icon" name="help" title=${i18nString(UIStrings.appIdExplainer)}
644
+ jslog=${VisualLogging.action('help').track({hover: true})}>
645
+ </devtools-icon>
646
+ <devtools-link href="https://developer.chrome.com/blog/pwa-manifest-id/"
647
+ .jslogContext=${'learn-more'}
648
+ ${ref(setFocusOnSection(i18nString(UIStrings.identity), output))}>
649
+ ${i18nString(UIStrings.learnMore)}
650
+ </devtools-link>
651
+ ${!hasId ? html`
652
+ <div class="multiline-value">
653
+ ${i18nTemplate(str_, UIStrings.appIdNote, {
654
+ PH1: html`<code>${recommendedId}</code>`,
655
+ PH2: html`<devtools-button class="inline-button" @click=${onCopy}
656
+ .iconName=${'copy'}
657
+ .variant=${Buttons.Button.Variant.ICON}
658
+ .size=${Buttons.Button.Size.SMALL}
659
+ .jslogContext=${'manifest.copy-id'}
660
+ .title=${i18nString(UIStrings.copyToClipboard)}>
661
+ </devtools-button>`,
662
+ })}
663
+ </div>` : nothing}
664
+ </devtools-report-value>` : nothing}
665
+ </div>`;
666
+ // clang-format on
661
667
  }
662
668
 
663
- function renderPresentation(
664
- presentationSection: UI.ReportView.Section, presentationData: PresentationSectionData): void {
669
+ function renderPresentation(presentationData: PresentationSectionData, output: ViewOutput): LitTemplate {
665
670
  const {
666
671
  startUrl,
667
672
  completeStartUrl,
@@ -673,42 +678,55 @@ function renderPresentation(
673
678
  hasNewNoteUrl,
674
679
  completeNewNoteUrl,
675
680
  } = presentationData;
676
- const fields: ReportSectionItem[] = [
677
- {
678
- title: i18nString(UIStrings.startUrl),
679
- label: i18nString(UIStrings.startUrl),
680
- content: completeStartUrl ? Components.Linkifier.Linkifier.linkifyURL(
681
- completeStartUrl, ({text: startUrl, tabStop: true, jslogContext: 'start-url'})) :
682
- nothing,
683
- },
684
- {
685
- title: i18nString(UIStrings.themeColor),
686
- content: themeColor ? html`<devtools-color-swatch .color=${themeColor}></devtools-color-swatch>` : nothing,
687
- },
688
- {
689
- title: i18nString(UIStrings.backgroundColor),
690
- content: backgroundColor ? html`<devtools-color-swatch .color=${backgroundColor}></devtools-color-swatch>` :
691
- nothing,
692
- },
693
- {title: i18nString(UIStrings.orientation), content: orientation},
694
- {title: i18nString(UIStrings.display), content: display},
695
- ];
696
- if (completeNewNoteUrl) {
697
- fields.push({
698
- title: i18nString(UIStrings.newNoteUrl),
699
- content: hasNewNoteUrl ?
700
- Components.Linkifier.Linkifier.linkifyURL(completeNewNoteUrl, ({text: newNoteUrl, tabStop: true})) :
701
- nothing,
702
- });
703
- }
704
- setSectionContents(fields, presentationSection);
681
+ // clang-format off
682
+ return html`${renderSectionHeader(i18nString(UIStrings.presentation), output)}
683
+ <div class="report-section" jslog=${VisualLogging.section('presentation')}>
684
+ <devtools-report-key>${i18nString(UIStrings.startUrl)}</devtools-report-key>
685
+ <devtools-report-value>
686
+ ${completeStartUrl ? (() => {
687
+ const link = linkifyURL(completeStartUrl, {text: startUrl, tabStop: true, jslogContext: 'start-url'});
688
+ output.focusOnSection.set(i18nString(UIStrings.presentation), () => link.focus());
689
+ return link;
690
+ })() : nothing}
691
+ </devtools-report-value>
692
+ <devtools-report-key>${i18nString(UIStrings.themeColor)}</devtools-report-key>
693
+ <devtools-report-value>${themeColor
694
+ ? html`<devtools-color-swatch .color=${themeColor}></devtools-color-swatch>`
695
+ : nothing}
696
+ </devtools-report-value>
697
+ <devtools-report-key>${i18nString(UIStrings.backgroundColor)}</devtools-report-key>
698
+ <devtools-report-value>${backgroundColor
699
+ ? html`<devtools-color-swatch .color=${backgroundColor}></devtools-color-swatch>`
700
+ : nothing}
701
+ </devtools-report-value>
702
+ <devtools-report-key>${i18nString(UIStrings.orientation)}</devtools-report-key>
703
+ <devtools-report-value>${orientation}</devtools-report-value>
704
+ <devtools-report-key>${i18nString(UIStrings.display)}</devtools-report-key>
705
+ <devtools-report-value>${display}</devtools-report-value>
706
+ ${completeNewNoteUrl ? html`
707
+ <devtools-report-key>${i18nString(UIStrings.newNoteUrl)}</devtools-report-key>
708
+ <devtools-report-value>${hasNewNoteUrl
709
+ ? linkifyURL(completeNewNoteUrl, {text: newNoteUrl, tabStop: true})
710
+ : nothing}
711
+ </devtools-report-value>
712
+ ` : nothing}
713
+ </div>
714
+ `;
715
+ // clang-format on
705
716
  }
706
717
 
707
- function renderProtocolHandlers(
708
- protocolHandlersView: ApplicationComponents.ProtocolHandlersView.ProtocolHandlersView,
709
- data: ProtocolHandlersSectionData): void {
710
- protocolHandlersView.protocolHandlers = data.protocolHandlers;
711
- protocolHandlersView.manifestLink = data.manifestLink;
718
+ function renderProtocolHandlers(data: ProtocolHandlersSectionData, output: ViewOutput): LitTemplate {
719
+ // clang-format off
720
+ return html`${renderSectionHeader(i18nString(UIStrings.protocolHandlers), output)}
721
+ <div class="report-row">
722
+ <devtools-widget .widgetConfig=${widgetConfig(
723
+ ApplicationComponents.ProtocolHandlersView.ProtocolHandlersView,
724
+ {protocolHandlers: data.protocolHandlers, manifestLink: data.manifestLink})}
725
+ ${ref(setFocusOnSection(i18nString(UIStrings.protocolHandlers), output))}>
726
+ </devtools-widget>
727
+ </div>
728
+ <devtools-report-divider></devtools-report-divider>`;
729
+ // clang-format on
712
730
  }
713
731
 
714
732
  function renderImage(imageSrc: string, imageUrl: string, naturalWidth: number): LitTemplate {
@@ -721,166 +739,164 @@ function renderImage(imageSrc: string, imageUrl: string, naturalWidth: number):
721
739
  // clang-format on
722
740
  }
723
741
 
724
- function renderIcons(iconsSection: UI.ReportView.Section, data: IconsSectionData): void {
725
- iconsSection.clearContent();
726
-
727
- const contents: ReportSectionItem[] = [
728
- // clang-format off
729
- {
730
- content: html`<devtools-checkbox class="mask-checkbox"
731
- jslog=${VisualLogging.toggle('show-minimal-safe-area-for-maskable-icons')
732
- .track({change: true})}
733
- @click=${(event: Event) => {
734
- iconsSection.setIconMasked((event.target as HTMLInputElement).checked);
735
- }}>
736
- ${i18nString(UIStrings.showOnlyTheMinimumSafeAreaFor)}
737
- </devtools-checkbox>`},
738
- // clang-format on
739
- {
740
- content: i18nTemplate(str_, UIStrings.needHelpReadOurS, {
741
- PH1: html`
742
- <devtools-link href="https://web.dev/maskable-icon/" .jslogContext=${'learn-more'}>
743
- ${i18nString(UIStrings.documentationOnMaskableIcons)}
744
- </devtools-link>`,
745
- }),
746
- },
747
- ];
748
- for (const [title, images] of data.icons) {
749
- const content = images.filter(icon => 'imageSrc' in icon)
750
- .map(icon => renderImage(icon.imageSrc, icon.imageUrl, icon.naturalWidth));
751
- contents.push({title, content, flexed: true});
752
- }
753
- setSectionContents(contents, iconsSection);
754
- }
755
-
756
- function renderShortcuts(
757
- reportView: UI.ReportView.ReportView, shortcutSections: UI.ReportView.Section[], data: ShortcutsSectionData): void {
758
- for (const shortcutsSection of shortcutSections) {
759
- shortcutsSection.detach(/** overrideHideOnDetach= */ true);
760
- }
761
- shortcutSections.length = 0;
762
-
763
- let shortcutIndex = 1;
764
- for (const shortcut of data.shortcuts) {
765
- const shortcutSection = reportView.appendSection(i18nString(UIStrings.shortcutS, {PH1: shortcutIndex}));
766
- shortcutSection.element.setAttribute('jslog', `${VisualLogging.section('shortcuts')}`);
767
- shortcutSections.push(shortcutSection);
768
-
769
- const fields: ReportSectionItem[] = [
770
- {title: i18nString(UIStrings.name), flexed: true, content: shortcut.name},
771
- ];
772
- if (shortcut.shortName) {
773
- fields.push({title: i18nString(UIStrings.shortName), flexed: true, content: shortcut.shortName});
774
- }
775
- if (shortcut.description) {
776
- fields.push({title: i18nString(UIStrings.description), flexed: true, content: shortcut.description});
777
- }
778
- fields.push({
779
- title: i18nString(UIStrings.url),
780
- flexed: true,
781
- content: Components.Linkifier.Linkifier.linkifyURL(
782
- shortcut.shortcutUrl, ({text: shortcut.url, tabStop: true, jslogContext: 'shortcut'})),
783
- });
784
-
785
- for (const [title, images] of shortcut.icons) {
786
- const content = images.filter(icon => 'imageSrc' in icon)
787
- .map(icon => renderImage(icon.imageSrc, icon.imageUrl, icon.naturalWidth));
788
- fields.push({title, content, flexed: true});
742
+ function setFocusOnSection(section: Platform.UIString.LocalizedString, output: ViewOutput): (e: Element|undefined) =>
743
+ void {
744
+ return (e: Element|undefined) => {
745
+ if (e instanceof HTMLElement) {
746
+ output.focusOnSection.set(section, () => e.focus());
789
747
  }
790
- setSectionContents(fields, shortcutSection);
791
- shortcutIndex++;
792
- }
748
+ };
793
749
  }
794
750
 
795
- function renderScreenshots(
796
- reportView: UI.ReportView.ReportView, screenshotsSections: UI.ReportView.Section[],
797
- data: ScreenshotsSectionData): void {
798
- for (const screenshotSection of screenshotsSections) {
799
- screenshotSection.detach(/** overrideHideOnDetach= */ true);
800
- }
801
- screenshotsSections.length = 0;
802
-
803
- let screenshotIndex = 1;
804
- for (const processedScreenshot of data.screenshots) {
805
- const {screenshot, processedImage} = processedScreenshot;
806
- const screenshotSection = reportView.appendSection(i18nString(UIStrings.screenshotS, {PH1: screenshotIndex}));
807
- screenshotsSections.push(screenshotSection);
808
- const fields: ReportSectionItem[] = [];
751
+ function renderIcons(
752
+ data: IconsSectionData, maskedIcons: boolean, onToggleIconMasked: (value: boolean) => void,
753
+ output: ViewOutput): LitTemplate {
754
+ // clang-format off
755
+ return html`${renderSectionHeader(i18nString(UIStrings.icons), output)}
756
+ <div class="report-section" jslog=${VisualLogging.section('icons')}>
757
+ <div class="report-row">
758
+ <devtools-checkbox class="mask-checkbox"
759
+ jslog=${VisualLogging.toggle('show-minimal-safe-area-for-maskable-icons')
760
+ .track({change: true})}
761
+ @click=${(event: Event) => onToggleIconMasked((event.target as HTMLInputElement).checked)}
762
+ ${ref(setFocusOnSection(i18nString(UIStrings.icons), output))}>
763
+ ${i18nString(UIStrings.showOnlyTheMinimumSafeAreaFor)}
764
+ </devtools-checkbox>
765
+ </div>
766
+ <div class="report-row">
767
+ ${i18nTemplate(str_, UIStrings.needHelpReadOurS, {
768
+ PH1: html`
769
+ <devtools-link href="https://web.dev/maskable-icon/" .jslogContext=${'learn-more'}>
770
+ ${i18nString(UIStrings.documentationOnMaskableIcons)}
771
+ </devtools-link>`,
772
+ })}
773
+ </div>
774
+ ${Array.from(data.icons).map(([title, images]: [string, ProcessedImageResource[]]) => {
775
+ return html`
776
+ <devtools-report-key>${title}</devtools-report-key>
777
+ <devtools-report-value class=${classMap({'show-mask': Boolean(maskedIcons)})}>
778
+ ${images.filter(icon => 'imageSrc' in icon)
779
+ .map(icon => renderImage(icon.imageSrc, icon.imageUrl, icon.naturalWidth))}
780
+ </devtools-report-value>
781
+ `;})}
782
+ </div>`;
783
+ // clang-format on
784
+ }
809
785
 
810
- if (screenshot.form_factor) {
811
- fields.push({title: i18nString(UIStrings.formFactor), flexed: true, content: screenshot.form_factor});
812
- }
813
- if (screenshot.label) {
814
- fields.push({title: i18nString(UIStrings.label), flexed: true, content: screenshot.label});
815
- }
816
- if (screenshot.platform) {
817
- fields.push({title: i18nString(UIStrings.platform), flexed: true, content: screenshot.platform});
818
- }
786
+ function renderShortcuts(data: ShortcutsSectionData): LitTemplate {
787
+ // clang-format off
788
+ return html`${data.shortcuts.map((shortcut, index) => html`
789
+ ${renderSectionHeader(i18nString(UIStrings.shortcutS, {PH1: index + 1}))}
790
+ <div class="report-section" jslog=${VisualLogging.section('shortcuts')}>
791
+ <devtools-report-key>${i18nString(UIStrings.name)}</devtools-report-key>
792
+ <devtools-report-value>${shortcut.name}</devtools-report-value>
793
+ ${shortcut.shortName ? html`
794
+ <devtools-report-key>${i18nString(UIStrings.shortName)}</devtools-report-key>
795
+ <devtools-report-value>${shortcut.shortName}</devtools-report-value>
796
+ ` : nothing}
797
+ ${shortcut.description ? html`
798
+ <devtools-report-key>${i18nString(UIStrings.description)}</devtools-report-key>
799
+ <devtools-report-value>${shortcut.description}</devtools-report-value>
800
+ ` : nothing}
801
+ <devtools-report-key>${i18nString(UIStrings.url)}</devtools-report-key>
802
+ <devtools-report-value>
803
+ ${linkifyURL(shortcut.shortcutUrl, {text: shortcut.url, tabStop: true, jslogContext: 'shortcut'})}
804
+ </devtools-report-value>
805
+ ${Array.from(shortcut.icons).map(([title, images]) => html`
806
+ <devtools-report-key>${title}</devtools-report-key>
807
+ <devtools-report-value>
808
+ ${images.filter(icon => 'imageSrc' in icon)
809
+ .map(icon => renderImage(icon.imageSrc, icon.imageUrl, icon.naturalWidth))}
810
+ </devtools-report-value>
811
+ `)}
812
+ </div>`)}`;
813
+ // clang-format on
814
+ }
819
815
 
820
- if ('imageSrc' in processedImage) {
821
- const content = renderImage(processedImage.imageSrc, processedImage.imageUrl, processedImage.naturalWidth);
822
- fields.push({title: processedImage.title, content, flexed: true});
823
- }
824
- setSectionContents(fields, screenshotSection);
825
- screenshotIndex++;
826
- }
816
+ function renderScreenshots(data: ScreenshotsSectionData): LitTemplate {
817
+ // clang-format off
818
+ return html`${data.screenshots.map(({screenshot, processedImage}, index) => html`
819
+ ${renderSectionHeader(i18nString(UIStrings.screenshotS, {PH1: index + 1}))}
820
+ <div class="report-section" jslog=${VisualLogging.section('screenshots')}>
821
+ ${screenshot.form_factor
822
+ ? html`<devtools-report-key>${i18nString(UIStrings.formFactor)}</devtools-report-key>
823
+ <devtools-report-value>${screenshot.form_factor}</devtools-report-value>`
824
+ : nothing}
825
+ ${screenshot.label
826
+ ? html`<devtools-report-key>${i18nString(UIStrings.label)}</devtools-report-key>
827
+ <devtools-report-value>${screenshot.label}</devtools-report-value>`
828
+ : nothing}
829
+ ${screenshot.platform
830
+ ? html`<devtools-report-key>${i18nString(UIStrings.platform)}</devtools-report-key>
831
+ <devtools-report-value>${screenshot.platform}</devtools-report-value>`
832
+ : nothing}
833
+ ${'imageSrc' in processedImage ? html`
834
+ <devtools-report-key>${processedImage.title}</devtools-report-key>
835
+ <devtools-report-value>
836
+ ${renderImage(processedImage.imageSrc, processedImage.imageUrl, processedImage.naturalWidth)}
837
+ </devtools-report-value>`
838
+ : nothing}
839
+ </div>
840
+ `)}`;
841
+ // clang-format on
827
842
  }
828
843
 
829
- function renderInstallability(
830
- installabilitySection: UI.ReportView.Section, installabilityErrors: Protocol.Page.InstallabilityError[]): void {
831
- installabilitySection.clearContent();
832
- installabilitySection.element.classList.toggle('hidden', !installabilityErrors.length);
833
- const errorMessages = getInstallabilityErrorMessages(installabilityErrors);
834
- setSectionContents(errorMessages.map(content => ({content})), installabilitySection);
844
+ function renderInstallability(installabilityErrors: Protocol.Page.InstallabilityError[]): LitTemplate {
845
+ return html`${renderSectionHeader(i18nString(UIStrings.installability))}
846
+ ${getInstallabilityErrorMessages(installabilityErrors).map(content => html`
847
+ <div class="report-row">
848
+ ${content}
849
+ </div>
850
+ `)}`;
835
851
  }
836
852
 
837
853
  function renderWindowControlsSection(
838
- windowControlsSection: UI.ReportView.Section, data: WindowControlsSectionData, selectedPlatform?: string,
839
- onSelectOs?: (selectedOS: SDK.OverlayModel.EmulatedOSType) => Promise<void>,
840
- onToggleWcoToolbar?: (enabled: boolean) => Promise<void>): void {
841
- const {hasWco, url} = data;
842
- const contents: ReportSectionItem[] = [];
843
- if (hasWco) {
844
- // clang-format off
845
- contents.push({content: html`
846
- <devtools-icon class="inline-icon" name="check-circle"></devtools-icon>
847
- ${i18nTemplate(str_, UIStrings.wcoFound, {
848
- PH1: html`<code class="wco">window-controls-overlay</code>`,
849
- PH2: html`<code>
850
- <devtools-link href="https://developer.mozilla.org/en-US/docs/Web/Manifest/display_override"
851
- .jslogContext=${'display-override'}>
852
- display-override
853
- </devtools-link>
854
- </code>`,
855
- PH3: html`${Components.Linkifier.Linkifier.linkifyURL(url)}`,
856
- })}`});
857
- // clang-format on
858
- if (selectedPlatform && onSelectOs && onToggleWcoToolbar) {
859
- const controls = renderWindowControls(selectedPlatform, onSelectOs, onToggleWcoToolbar);
860
- contents.push(controls);
861
- }
862
- } else {
863
- // clang-format off
864
- contents.push({content: html`
865
- <devtools-icon class="inline-icon" name="info"></devtools-icon>
866
- ${i18nTemplate(str_, UIStrings.wcoNotFound, {
867
- PH1: html`<code>
868
- <devtools-link href="https://developer.mozilla.org/en-US/docs/Web/Manifest/display_override"
869
- .jslogContext=${'display-override'}>
870
- display-override
871
- </devtools-link>
872
- </code>`})}`});
873
- // clang-format on
874
- }
854
+ data: WindowControlsSectionData, selectedPlatform: string|undefined,
855
+ onSelectOs: ((selectedOS: SDK.OverlayModel.EmulatedOSType) => Promise<void>)|undefined,
856
+ onToggleWcoToolbar: ((enabled: boolean) => Promise<void>)|undefined, output: ViewOutput): LitTemplate {
875
857
  // clang-format off
876
- contents.push({content: i18nTemplate(str_, UIStrings.wcoNeedHelpReadMore, { PH1: html`<devtools-link
877
- href="https://learn.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/window-controls-overlay"
878
- .jslogContext=${'customize-pwa-tittle-bar'}>
879
- ${i18nString(UIStrings.customizePwaTitleBar)}
880
- </devtools-link>`})});
858
+ return html`
859
+ ${renderSectionHeader(i18nString(UIStrings.windowControlsOverlay), output)}
860
+ <div class="report-section" jslog=${VisualLogging.section('window-controls-overlay')}>
861
+ ${data?.hasWco && output ? html`
862
+ <div class="report-row">
863
+ <devtools-icon class="inline-icon" name="check-circle"></devtools-icon>
864
+ ${i18nTemplate(str_, UIStrings.wcoFound, {
865
+ PH1: html`<code class="wco">window-controls-overlay</code>`,
866
+ PH2: html`<code>
867
+ <devtools-link
868
+ href="https://developer.mozilla.org/en-US/docs/Web/Manifest/display_override"
869
+ .jslogContext=${'display-override'}
870
+ ${ref(setFocusOnSection(i18nString(UIStrings.windowControlsOverlay), output))}>
871
+ display-override
872
+ </devtools-link>
873
+ </code>`,
874
+ PH3: html`${Components.Linkifier.Linkifier.linkifyURL(data.url)}`,
875
+ })}
876
+ </div>
877
+ ${selectedPlatform && onSelectOs && onToggleWcoToolbar ?
878
+ renderWindowControls(selectedPlatform, onSelectOs, onToggleWcoToolbar) :
879
+ nothing}` : html`
880
+ <div class="report-row">
881
+ <devtools-icon class="inline-icon" name="info"></devtools-icon>
882
+ ${i18nTemplate(str_, UIStrings.wcoNotFound, {PH1: html`<code>
883
+ <devtools-link
884
+ href="https://developer.mozilla.org/en-US/docs/Web/Manifest/display_override"
885
+ .jslogContext=${'display-override'}
886
+ ${ref(setFocusOnSection(i18nString(UIStrings.windowControlsOverlay), output))}>
887
+ display-override
888
+ </devtools-link>
889
+ </code>`})}
890
+ </div>`}
891
+ <div class="report-row">
892
+ ${i18nTemplate(str_, UIStrings.wcoNeedHelpReadMore, {PH1: html`<devtools-link
893
+ href="https://learn.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/window-controls-overlay"
894
+ .jslogContext=${'customize-pwa-tittle-bar'}>
895
+ ${i18nString(UIStrings.customizePwaTitleBar)}
896
+ </devtools-link>`})}
897
+ </div>
898
+ </div>`;
881
899
  // clang-format on
882
- windowControlsSection.clearContent();
883
- setSectionContents(contents, windowControlsSection);
884
900
  }
885
901
 
886
902
  function getInstallabilityErrorMessages(installabilityErrors: Protocol.Page.InstallabilityError[]): string[] {
@@ -984,9 +1000,9 @@ function getInstallabilityErrorMessages(installabilityErrors: Protocol.Page.Inst
984
1000
 
985
1001
  function renderWindowControls(
986
1002
  selectedPlatform: string, onSelectOs: (selectedOS: SDK.OverlayModel.EmulatedOSType) => Promise<void>,
987
- onToggleWcoToolbar: (enabled: boolean) => Promise<void>): ReportSectionItem {
1003
+ onToggleWcoToolbar: (enabled: boolean) => Promise<void>): LitTemplate {
988
1004
  // clang-format off
989
- return {content: html`
1005
+ return html`<div class="report-row">
990
1006
  <devtools-checkbox @click=${(event: Event) => onToggleWcoToolbar((event.target as HTMLInputElement).checked)}
991
1007
  title=${i18nString(UIStrings.selectWindowControlsOverlayEmulationOs)}>
992
1008
  ${i18nString(UIStrings.selectWindowControlsOverlayEmulationOs)}
@@ -1010,33 +1026,19 @@ function renderWindowControls(
1010
1026
  jslog=${VisualLogging.item('linux').track({click: true})}>
1011
1027
  Linux
1012
1028
  </option>
1013
- </select>`};
1029
+ </select>
1030
+ </div>`;
1014
1031
  // clang-format on
1015
1032
  }
1016
1033
 
1017
- function setSectionContents(items: ReportSectionItem[], section: UI.ReportView.Section): void {
1018
- for (const item of items) {
1019
- if (!item.title) {
1020
- render(item.content, section.appendRow());
1021
- continue;
1022
- }
1023
- const element = item.flexed ? section.appendFlexedField(item.title) : section.appendField(item.title);
1024
- if (item.label) {
1025
- UI.ARIAUtils.setLabel(element, item.label);
1026
- }
1027
- render(item.content, element);
1028
- }
1029
- }
1030
-
1031
1034
  interface ViewInput {
1032
- emptyView: UI.EmptyWidget.EmptyWidget;
1033
- reportView: UI.ReportView.ReportView;
1035
+ isEmpty?: boolean;
1034
1036
  errorsSection?: UI.ReportView.Section;
1035
1037
  installabilitySection?: UI.ReportView.Section;
1036
1038
  identitySection?: UI.ReportView.Section;
1037
1039
  presentationSection?: UI.ReportView.Section;
1038
- protocolHandlersView?: ApplicationComponents.ProtocolHandlersView.ProtocolHandlersView;
1039
1040
  iconsSection?: UI.ReportView.Section;
1041
+ maskedIcons?: boolean;
1040
1042
  windowControlsSection?: UI.ReportView.Section;
1041
1043
  shortcutSections?: UI.ReportView.Section[];
1042
1044
  screenshotsSections?: UI.ReportView.Section[];
@@ -1056,22 +1058,20 @@ interface ViewInput {
1056
1058
  selectedPlatform?: string;
1057
1059
  onSelectOs?: (selectedOS: SDK.OverlayModel.EmulatedOSType) => Promise<void>;
1058
1060
  onToggleWcoToolbar?: (enabled: boolean) => Promise<void>;
1061
+ onCopyId?: () => void;
1062
+ onToggleIconMasked?: (masked: boolean) => void;
1059
1063
  }
1060
1064
 
1061
- type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
1065
+ interface ViewOutput {
1066
+ scrollToSection: Map<string, () => void>;
1067
+ focusOnSection: Map<string, () => void>;
1068
+ }
1069
+
1070
+ type View = (input: ViewInput, output: ViewOutput, target: HTMLElement) => void;
1062
1071
 
1063
- export const DEFAULT_VIEW: View = (input, _output, _target) => {
1072
+ export const DEFAULT_VIEW: View = (input, output, target) => {
1064
1073
  const {
1065
- reportView,
1066
- errorsSection,
1067
- installabilitySection,
1068
- identitySection,
1069
- presentationSection,
1070
- protocolHandlersView,
1071
- iconsSection,
1072
- windowControlsSection,
1073
- shortcutSections,
1074
- screenshotsSections,
1074
+ isEmpty,
1075
1075
  identityData,
1076
1076
  presentationData,
1077
1077
  protocolHandlersData,
@@ -1082,67 +1082,57 @@ export const DEFAULT_VIEW: View = (input, _output, _target) => {
1082
1082
  warnings,
1083
1083
  errors,
1084
1084
  imageErrors,
1085
+ maskedIcons,
1085
1086
  windowControlsData,
1086
1087
  selectedPlatform,
1087
1088
  onSelectOs,
1088
1089
  onToggleWcoToolbar,
1090
+ onToggleIconMasked,
1091
+ onCopyId,
1092
+ url,
1089
1093
  } = input;
1090
- if (identitySection && identityData) {
1091
- renderIdentity(identitySection, identityData);
1092
- }
1093
- if (presentationSection && presentationData) {
1094
- renderPresentation(presentationSection, presentationData);
1095
- }
1096
- if (protocolHandlersView && protocolHandlersData) {
1097
- renderProtocolHandlers(protocolHandlersView, protocolHandlersData);
1098
- }
1099
- if (iconsSection && iconsData) {
1100
- renderIcons(iconsSection, iconsData);
1101
- }
1102
- if (shortcutSections && shortcutsData) {
1103
- renderShortcuts(reportView, shortcutSections, shortcutsData);
1104
- }
1105
- if (screenshotsSections && screenshotsData) {
1106
- renderScreenshots(reportView, screenshotsSections, screenshotsData);
1107
- }
1108
- if (installabilitySection && installabilityErrors) {
1109
- renderInstallability(installabilitySection, installabilityErrors);
1110
- }
1111
- if (windowControlsSection && windowControlsData) {
1112
- renderWindowControlsSection(
1113
- windowControlsSection, windowControlsData, selectedPlatform, onSelectOs, onToggleWcoToolbar);
1114
- }
1115
- if (errorsSection) {
1116
- renderErrors(errorsSection, warnings, errors, imageErrors);
1117
- }
1094
+ // clang-format off
1095
+ render(html`
1096
+ <style>${appManifestViewStyles}</style>
1097
+ <style>${UI.inspectorCommonStyles}</style>
1098
+ ${isEmpty ? html`
1099
+ <devtools-widget .widgetConfig=${widgetConfig(UI.EmptyWidget.EmptyWidget, {
1100
+ header: i18nString(UIStrings.noManifestDetected),
1101
+ text: i18nString(UIStrings.manifestDescription),
1102
+ link: 'https://web.dev/add-manifest/' as Platform.DevToolsPath.UrlString
1103
+ })}></devtools-widget>` : html`
1104
+ <devtools-report .data=${{reportTitle: i18nString(UIStrings.appManifest), reportUrl: url}}>
1105
+ ${renderErrors(warnings, errors, imageErrors, output)}
1106
+ ${installabilityErrors?.length ? renderInstallability(installabilityErrors) : nothing}
1107
+ ${identityData && onCopyId ? renderIdentity(identityData, onCopyId, output) : nothing}
1108
+ ${presentationData ? renderPresentation(presentationData, output) : nothing}
1109
+ ${protocolHandlersData ? renderProtocolHandlers(protocolHandlersData, output) : nothing}
1110
+ ${iconsData && onToggleIconMasked && maskedIcons ?
1111
+ renderIcons(iconsData, maskedIcons, onToggleIconMasked, output) : nothing}
1112
+ ${windowControlsData && output ? renderWindowControlsSection(
1113
+ windowControlsData, selectedPlatform, onSelectOs, onToggleWcoToolbar, output) : nothing}
1114
+ ${shortcutsData ? renderShortcuts(shortcutsData) : nothing}
1115
+ ${screenshotsData ? renderScreenshots(screenshotsData) : nothing}
1116
+ </devtools-report>`}`, target);
1117
+ // clang-format on
1118
1118
  };
1119
1119
 
1120
1120
  export class AppManifestView extends Common.ObjectWrapper.eventMixin<EventTypes, typeof UI.Widget.VBox>(UI.Widget.VBox)
1121
1121
  implements SDK.TargetManager.Observer {
1122
- private readonly emptyView: UI.EmptyWidget.EmptyWidget;
1123
- private readonly reportView: UI.ReportView.ReportView;
1124
- private readonly errorsSection: UI.ReportView.Section;
1125
- private readonly installabilitySection: UI.ReportView.Section;
1126
- private readonly identitySection: UI.ReportView.Section;
1127
- private readonly presentationSection: UI.ReportView.Section;
1128
- private readonly iconsSection: UI.ReportView.Section;
1129
- private readonly windowControlsSection: UI.ReportView.Section;
1130
- private readonly protocolHandlersSection: UI.ReportView.Section;
1131
- private readonly shortcutSections: UI.ReportView.Section[];
1132
- private readonly screenshotsSections: UI.ReportView.Section[];
1133
1122
  private registeredListeners: Common.EventTarget.EventDescriptor[];
1134
1123
  private target?: SDK.Target.Target;
1135
1124
  private resourceTreeModel?: SDK.ResourceTreeModel.ResourceTreeModel|null;
1136
1125
  private serviceWorkerManager?: SDK.ServiceWorkerManager.ServiceWorkerManager|null;
1137
1126
  private overlayModel?: SDK.OverlayModel.OverlayModel|null;
1138
- private protocolHandlersView: ApplicationComponents.ProtocolHandlersView.ProtocolHandlersView;
1139
1127
  private manifestUrl: Platform.DevToolsPath.UrlString;
1140
1128
  private manifestData: string|null;
1141
1129
  private manifestErrors: Protocol.Page.AppManifestError[];
1142
1130
  private installabilityErrors: Protocol.Page.InstallabilityError[];
1143
1131
  private appIdResponse: Protocol.Page.GetAppIdResponse|null;
1144
1132
  private wcoToolbarEnabled = false;
1133
+ private maskedIcons = false;
1145
1134
  private readonly view: View;
1135
+ private readonly output: ViewOutput = {scrollToSection: new Map(), focusOnSection: new Map()};
1146
1136
 
1147
1137
  constructor(view: View = DEFAULT_VIEW) {
1148
1138
  super({
@@ -1150,39 +1140,6 @@ export class AppManifestView extends Common.ObjectWrapper.eventMixin<EventTypes,
1150
1140
  useShadowDom: true,
1151
1141
  });
1152
1142
  this.view = view;
1153
- this.registerRequiredCSS(appManifestViewStyles);
1154
-
1155
- this.contentElement.classList.add('manifest-container');
1156
-
1157
- this.emptyView = new UI.EmptyWidget.EmptyWidget(
1158
- i18nString(UIStrings.noManifestDetected), i18nString(UIStrings.manifestDescription));
1159
- this.emptyView.link = 'https://web.dev/add-manifest/' as Platform.DevToolsPath.UrlString;
1160
-
1161
- this.emptyView.show(this.contentElement);
1162
- this.emptyView.hideWidget();
1163
-
1164
- this.reportView = new UI.ReportView.ReportView(i18nString(UIStrings.appManifest));
1165
- this.reportView.registerRequiredCSS(appManifestViewStyles);
1166
- this.reportView.element.classList.add('manifest-view-header');
1167
- this.reportView.show(this.contentElement);
1168
- this.reportView.hideWidget();
1169
-
1170
- this.errorsSection =
1171
- this.reportView.appendSection(i18nString(UIStrings.errorsAndWarnings), undefined, 'errors-and-warnings');
1172
- this.installabilitySection =
1173
- this.reportView.appendSection(i18nString(UIStrings.installability), undefined, 'installability');
1174
- this.identitySection = this.reportView.appendSection(i18nString(UIStrings.identity), 'undefined,identity');
1175
- this.presentationSection =
1176
- this.reportView.appendSection(i18nString(UIStrings.presentation), 'undefined,presentation');
1177
- this.protocolHandlersSection =
1178
- this.reportView.appendSection(i18nString(UIStrings.protocolHandlers), 'undefined,protocol-handlers');
1179
- this.protocolHandlersView = new ApplicationComponents.ProtocolHandlersView.ProtocolHandlersView();
1180
- this.protocolHandlersView.show(this.protocolHandlersSection.getFieldElement());
1181
- this.iconsSection = this.reportView.appendSection(i18nString(UIStrings.icons), 'report-section-icons', 'icons');
1182
- this.windowControlsSection =
1183
- this.reportView.appendSection(UIStrings.windowControlsOverlay, undefined, 'window-controls-overlay');
1184
- this.shortcutSections = [];
1185
- this.screenshotsSections = [];
1186
1143
 
1187
1144
  SDK.TargetManager.TargetManager.instance().observeTargets(this);
1188
1145
  this.registeredListeners = [];
@@ -1194,18 +1151,36 @@ export class AppManifestView extends Common.ObjectWrapper.eventMixin<EventTypes,
1194
1151
  this.appIdResponse = null;
1195
1152
  }
1196
1153
 
1197
- getStaticSections(): UI.ReportView.Section[] {
1154
+ scrollToSection(sectionTitle: string): void {
1155
+ const handler = this.output.scrollToSection.get(sectionTitle);
1156
+ if (!handler) {
1157
+ return;
1158
+ }
1159
+ handler();
1160
+ UI.ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.onInvokeAlert, {PH1: sectionTitle}));
1161
+ }
1162
+
1163
+ focusOnSection(sectionTitle: string): boolean {
1164
+ const handler = this.output.focusOnSection.get(sectionTitle);
1165
+ if (!handler) {
1166
+ return false;
1167
+ }
1168
+ handler();
1169
+ return true;
1170
+ }
1171
+
1172
+ getStaticSections(): Array<{title: string, jslogContext: string|undefined}> {
1198
1173
  return [
1199
- this.identitySection,
1200
- this.presentationSection,
1201
- this.protocolHandlersSection,
1202
- this.iconsSection,
1203
- this.windowControlsSection,
1174
+ {title: i18nString(UIStrings.identity), jslogContext: 'identity'},
1175
+ {title: i18nString(UIStrings.presentation), jslogContext: 'presentation'},
1176
+ {title: i18nString(UIStrings.protocolHandlers), jslogContext: 'protocol-handlers'},
1177
+ {title: i18nString(UIStrings.icons), jslogContext: 'icons'},
1178
+ {title: i18nString(UIStrings.windowControlsOverlay), jslogContext: 'window-controls'},
1204
1179
  ];
1205
1180
  }
1206
1181
 
1207
1182
  getManifestElement(): Element {
1208
- return this.reportView.getHeaderElement();
1183
+ return this.contentElement;
1209
1184
  }
1210
1185
 
1211
1186
  targetAdded(target: SDK.Target.Target): void {
@@ -1282,23 +1257,14 @@ export class AppManifestView extends Common.ObjectWrapper.eventMixin<EventTypes,
1282
1257
  const appId = appIdResponse?.appId || null;
1283
1258
  const recommendedId = appIdResponse?.recommendedId || null;
1284
1259
  if ((!data || data === '{}') && !errors.length) {
1285
- this.emptyView.showWidget();
1286
- this.reportView.hideWidget();
1287
- this.view({emptyView: this.emptyView, reportView: this.reportView}, undefined, this.contentElement);
1260
+ this.view({isEmpty: true}, this.output, this.contentElement);
1288
1261
  this.dispatchEventToListeners(Events.MANIFEST_DETECTED, false);
1289
1262
  return;
1290
1263
  }
1291
- this.emptyView.hideWidget();
1292
- this.reportView.showWidget();
1293
1264
  this.dispatchEventToListeners(Events.MANIFEST_DETECTED, true);
1294
1265
 
1295
- const link = Components.Linkifier.Linkifier.linkifyURL(url, {tabStop: true});
1296
- this.reportView.setURL(link);
1297
-
1298
1266
  if (!data) {
1299
- this.view(
1300
- {emptyView: this.emptyView, reportView: this.reportView, errorsSection: this.errorsSection, errors},
1301
- undefined, this.contentElement);
1267
+ this.view({url, errors}, this.output, this.contentElement);
1302
1268
  return;
1303
1269
  }
1304
1270
 
@@ -1336,19 +1302,17 @@ export class AppManifestView extends Common.ObjectWrapper.eventMixin<EventTypes,
1336
1302
  (selectedOS: SDK.OverlayModel.EmulatedOSType) => this.onSelectOs(selectedOS, windowControlsData.themeColor) :
1337
1303
  undefined;
1338
1304
  const onToggleWcoToolbar = this.overlayModel ? (enabled: boolean) => this.onToggleWcoToolbar(enabled) : undefined;
1305
+ const onCopyId = recommendedId ? () : void => {
1306
+ UI.ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.copiedToClipboard, {PH1: recommendedId}));
1307
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(recommendedId);
1308
+ }: undefined;
1309
+ const onToggleIconMasked = (masked: boolean): void => {
1310
+ this.maskedIcons = masked;
1311
+ this.requestUpdate();
1312
+ };
1339
1313
  this.view(
1340
1314
  {
1341
- emptyView: this.emptyView,
1342
- reportView: this.reportView,
1343
- errorsSection: this.errorsSection,
1344
- installabilitySection: this.installabilitySection,
1345
- identitySection: this.identitySection,
1346
- presentationSection: this.presentationSection,
1347
- protocolHandlersView: this.protocolHandlersView,
1348
- iconsSection: this.iconsSection,
1349
- windowControlsSection: this.windowControlsSection,
1350
- shortcutSections: this.shortcutSections,
1351
- screenshotsSections: this.screenshotsSections,
1315
+ maskedIcons: this.maskedIcons,
1352
1316
  parsedManifest,
1353
1317
  url,
1354
1318
  identityData,
@@ -1365,8 +1329,10 @@ export class AppManifestView extends Common.ObjectWrapper.eventMixin<EventTypes,
1365
1329
  selectedPlatform,
1366
1330
  onSelectOs,
1367
1331
  onToggleWcoToolbar,
1332
+ onCopyId,
1333
+ onToggleIconMasked,
1368
1334
  },
1369
- undefined, this.contentElement);
1335
+ this.output, this.contentElement);
1370
1336
  }
1371
1337
 
1372
1338
  private stringProperty(parsedManifest: Manifest, name: keyof Manifest): string {
@@ -1396,6 +1362,8 @@ export class AppManifestView extends Common.ObjectWrapper.eventMixin<EventTypes,
1396
1362
  initiatorUrl: this.target.inspectedURL(),
1397
1363
  },
1398
1364
  /* isBinary=*/ true);
1365
+ // Just loading the image, not building UI.
1366
+ /* eslint-disable @devtools/no-imperative-dom-api */
1399
1367
  const image = document.createElement('img');
1400
1368
  const result = new Promise((resolve, reject) => {
1401
1369
  image.onload = resolve;
@@ -1405,6 +1373,7 @@ export class AppManifestView extends Common.ObjectWrapper.eventMixin<EventTypes,
1405
1373
  // does not work, we can parse mimeType out of the response headers
1406
1374
  // using front_end/core/platform/MimeType.ts.
1407
1375
  image.src = 'data:application/octet-stream;base64,' + await Common.Base64.encode(content);
1376
+ /* eslint-enable @devtools/no-imperative-dom-api */
1408
1377
  try {
1409
1378
  await result;
1410
1379
  return {naturalWidth: image.naturalWidth, naturalHeight: image.naturalHeight, src: image.src};