chrome-devtools-frontend 1.0.1526630 → 1.0.1528866

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 (319) hide show
  1. package/docs/ui_engineering.md +159 -0
  2. package/eslint.config.mjs +6 -1
  3. package/front_end/core/i18n/i18nImpl.ts +6 -1
  4. package/front_end/core/protocol_client/protocol_client.ts +1 -1
  5. package/front_end/core/root/Runtime.ts +28 -4
  6. package/front_end/core/sdk/CSSMatchedStyles.ts +50 -7
  7. package/front_end/core/sdk/CSSRule.ts +35 -6
  8. package/front_end/core/sdk/Connections.ts +2 -1
  9. package/front_end/core/sdk/DOMModel.ts +4 -0
  10. package/front_end/core/sdk/DebuggerModel.ts +5 -1
  11. package/front_end/core/sdk/NetworkManager.ts +214 -31
  12. package/front_end/core/sdk/PreloadingModel.ts +82 -17
  13. package/front_end/core/sdk/RehydratingConnection.snapshot.txt +1 -1
  14. package/front_end/core/sdk/RehydratingConnection.ts +29 -4
  15. package/front_end/core/sdk/ScopeTreeCache.ts +8 -3
  16. package/front_end/core/sdk/SourceMap.ts +37 -11
  17. package/front_end/core/sdk/SourceMapManager.ts +13 -2
  18. package/front_end/core/sdk/SourceMapScopesInfo.ts +17 -0
  19. package/front_end/core/sdk/TargetManager.ts +0 -22
  20. package/front_end/core/sdk/TraceObject.ts +8 -7
  21. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +81 -0
  22. package/front_end/entrypoints/inspector_main/InspectorMain.ts +3 -1
  23. package/front_end/entrypoints/main/GlobalAiButton.ts +1 -0
  24. package/front_end/entrypoints/main/MainImpl.ts +20 -25
  25. package/front_end/generated/InspectorBackendCommands.js +3 -2
  26. package/front_end/generated/protocol.ts +17 -3
  27. package/front_end/models/ai_assistance/BuiltInAi.ts +111 -0
  28. package/front_end/models/ai_assistance/ai_assistance.ts +53 -24
  29. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +105 -0
  30. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +6 -1
  31. package/front_end/models/extensions/ExtensionView.ts +3 -0
  32. package/front_end/models/javascript_metadata/NativeFunctions.js +23 -27
  33. package/front_end/models/live-metrics/web-vitals-injected/web-vitals-injected.ts +31 -29
  34. package/front_end/models/persistence/EditFileSystemView.ts +1 -0
  35. package/front_end/models/source_map_scopes/NamesResolver.ts +5 -11
  36. package/front_end/models/stack_trace/Trie.ts +9 -0
  37. package/front_end/models/trace/lantern/types/Lantern.ts +1 -1
  38. package/front_end/panels/accessibility/AXBreadcrumbsPane.ts +1 -0
  39. package/front_end/panels/accessibility/AccessibilitySidebarView.ts +1 -0
  40. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +120 -113
  41. package/front_end/panels/ai_assistance/PatchWidget.ts +9 -8
  42. package/front_end/panels/ai_assistance/SelectWorkspaceDialog.ts +2 -0
  43. package/front_end/panels/ai_assistance/components/ChatView.ts +29 -29
  44. package/front_end/panels/ai_assistance/components/UserActionRow.ts +1 -0
  45. package/front_end/panels/animation/AnimationTimeline.ts +1 -0
  46. package/front_end/panels/application/CookieItemsView.ts +1 -0
  47. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
  48. package/front_end/panels/application/ServiceWorkerCacheViews.ts +2 -0
  49. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +11 -5
  50. package/front_end/panels/application/preloading/components/PreloadingMismatchedHeadersGrid.ts +2 -2
  51. package/front_end/panels/application/preloading/components/PreloadingString.ts +7 -5
  52. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +22 -10
  53. package/front_end/panels/changes/CombinedDiffView.ts +1 -0
  54. package/front_end/panels/console/ConsoleInsightTeaser.ts +106 -0
  55. package/front_end/panels/console/ConsolePanel.ts +2 -0
  56. package/front_end/panels/console/ConsolePrompt.ts +12 -2
  57. package/front_end/panels/console/ConsoleSidebar.ts +1 -1
  58. package/front_end/panels/console/ConsoleView.ts +12 -0
  59. package/front_end/panels/console/ConsoleViewMessage.ts +27 -0
  60. package/front_end/panels/{explain → console}/PromptBuilder.ts +12 -7
  61. package/front_end/panels/console/console.ts +6 -0
  62. package/front_end/panels/console/consoleInsightTeaser.css +55 -0
  63. package/front_end/panels/coverage/CoverageListView.ts +29 -11
  64. package/front_end/panels/coverage/CoverageView.ts +292 -284
  65. package/front_end/panels/coverage/coverageView.css +17 -0
  66. package/front_end/panels/elements/ComputedStyleWidget.ts +1 -0
  67. package/front_end/panels/elements/LayoutPane.ts +1 -0
  68. package/front_end/panels/elements/NodeStackTraceWidget.ts +1 -0
  69. package/front_end/panels/elements/StylePropertyTreeElement.ts +5 -1
  70. package/front_end/panels/elements/stylePropertiesTreeOutline.css +17 -0
  71. package/front_end/panels/emulation/DeviceModeView.ts +2 -0
  72. package/front_end/panels/explain/ActionDelegate.ts +1 -2
  73. package/front_end/panels/explain/components/ConsoleInsight.ts +14 -12
  74. package/front_end/panels/explain/explain.ts +0 -1
  75. package/front_end/panels/js_timeline/js_timeline-meta.ts +1 -1
  76. package/front_end/panels/layer_viewer/Layers3DView.ts +2 -0
  77. package/front_end/panels/lighthouse/LighthouseReportSelector.ts +1 -0
  78. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorPane.ts +1 -0
  79. package/front_end/panels/media/MainView.ts +1 -0
  80. package/front_end/panels/media/TickingFlameChart.ts +2 -0
  81. package/front_end/panels/network/BlockedURLsPane.ts +111 -85
  82. package/front_end/panels/network/EventSourceMessagesView.ts +1 -0
  83. package/front_end/panels/network/NetworkItemView.ts +1 -0
  84. package/front_end/panels/network/NetworkLogView.ts +9 -7
  85. package/front_end/panels/network/NetworkOverview.ts +1 -0
  86. package/front_end/panels/network/RequestCookiesView.ts +1 -0
  87. package/front_end/panels/network/RequestHTMLView.ts +1 -0
  88. package/front_end/panels/network/RequestInitiatorView.ts +1 -0
  89. package/front_end/panels/network/RequestPayloadView.ts +1 -0
  90. package/front_end/panels/network/RequestPreviewView.ts +1 -0
  91. package/front_end/panels/network/RequestResponseView.ts +1 -0
  92. package/front_end/panels/network/RequestTimingView.ts +2 -0
  93. package/front_end/panels/network/ResourceDirectSocketChunkView.ts +1 -0
  94. package/front_end/panels/network/ResourceWebSocketFrameView.ts +1 -0
  95. package/front_end/panels/network/components/RequestHeadersView.ts +2 -0
  96. package/front_end/panels/network/components/RequestTrustTokensView.ts +2 -0
  97. package/front_end/panels/performance_monitor/PerformanceMonitor.ts +2 -0
  98. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +2 -0
  99. package/front_end/panels/profiler/HeapSnapshotView.ts +7 -0
  100. package/front_end/panels/profiler/IsolateSelector.ts +1 -0
  101. package/front_end/panels/profiler/LiveHeapProfileView.ts +1 -0
  102. package/front_end/panels/profiler/ProfileView.ts +1 -0
  103. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +1 -0
  104. package/front_end/panels/recorder/RecorderPanel.ts +2 -0
  105. package/front_end/panels/screencast/ScreencastView.ts +1 -0
  106. package/front_end/panels/search/SearchView.ts +1 -0
  107. package/front_end/panels/settings/AISettingsTab.ts +3 -3
  108. package/front_end/panels/settings/WorkspaceSettingsTab.ts +2 -0
  109. package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +2 -2
  110. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +12 -0
  111. package/front_end/panels/sources/BreakpointsView.ts +1 -0
  112. package/front_end/panels/sources/DebuggerPlugin.ts +1 -0
  113. package/front_end/panels/sources/UISourceCodeFrame.ts +17 -2
  114. package/front_end/panels/timeline/README.md +2 -2
  115. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +1 -1
  116. package/front_end/panels/timeline/TimelineFlameChartView.ts +4 -3
  117. package/front_end/panels/timeline/TimelineLayersView.ts +1 -0
  118. package/front_end/panels/timeline/TimelinePaintProfilerView.ts +114 -37
  119. package/front_end/panels/timeline/TimelinePanel.ts +43 -62
  120. package/front_end/panels/timeline/TimelineTreeView.ts +1 -0
  121. package/front_end/panels/timeline/components/LiveMetricsView.ts +4 -8
  122. package/front_end/panels/timeline/components/Sidebar.ts +2 -0
  123. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
  124. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +7 -7
  125. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +1 -1
  126. package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +4 -4
  127. package/front_end/panels/web_audio/WebAudioView.ts +1 -0
  128. package/front_end/third_party/chromium/README.chromium +1 -1
  129. package/front_end/third_party/lighthouse/README.chromium +2 -2
  130. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1530 -2426
  131. package/front_end/third_party/lighthouse/locales/ar-XB.json +107 -455
  132. package/front_end/third_party/lighthouse/locales/ar.json +107 -455
  133. package/front_end/third_party/lighthouse/locales/bg.json +96 -444
  134. package/front_end/third_party/lighthouse/locales/ca.json +96 -444
  135. package/front_end/third_party/lighthouse/locales/cs.json +96 -444
  136. package/front_end/third_party/lighthouse/locales/da.json +96 -444
  137. package/front_end/third_party/lighthouse/locales/de.json +96 -444
  138. package/front_end/third_party/lighthouse/locales/el.json +96 -444
  139. package/front_end/third_party/lighthouse/locales/en-GB.json +96 -444
  140. package/front_end/third_party/lighthouse/locales/en-US.json +116 -467
  141. package/front_end/third_party/lighthouse/locales/en-XA.json +93 -441
  142. package/front_end/third_party/lighthouse/locales/en-XL.json +116 -467
  143. package/front_end/third_party/lighthouse/locales/es-419.json +96 -444
  144. package/front_end/third_party/lighthouse/locales/es.json +96 -444
  145. package/front_end/third_party/lighthouse/locales/fi.json +96 -444
  146. package/front_end/third_party/lighthouse/locales/fil.json +96 -444
  147. package/front_end/third_party/lighthouse/locales/fr.json +96 -444
  148. package/front_end/third_party/lighthouse/locales/he.json +118 -466
  149. package/front_end/third_party/lighthouse/locales/hi.json +96 -444
  150. package/front_end/third_party/lighthouse/locales/hr.json +100 -448
  151. package/front_end/third_party/lighthouse/locales/hu.json +96 -444
  152. package/front_end/third_party/lighthouse/locales/id.json +96 -444
  153. package/front_end/third_party/lighthouse/locales/it.json +96 -444
  154. package/front_end/third_party/lighthouse/locales/ja.json +96 -444
  155. package/front_end/third_party/lighthouse/locales/ko.json +97 -445
  156. package/front_end/third_party/lighthouse/locales/lt.json +96 -444
  157. package/front_end/third_party/lighthouse/locales/lv.json +97 -445
  158. package/front_end/third_party/lighthouse/locales/nl.json +96 -444
  159. package/front_end/third_party/lighthouse/locales/no.json +96 -444
  160. package/front_end/third_party/lighthouse/locales/pl.json +96 -444
  161. package/front_end/third_party/lighthouse/locales/pt-PT.json +96 -444
  162. package/front_end/third_party/lighthouse/locales/pt.json +97 -445
  163. package/front_end/third_party/lighthouse/locales/ro.json +97 -445
  164. package/front_end/third_party/lighthouse/locales/ru.json +96 -444
  165. package/front_end/third_party/lighthouse/locales/sk.json +96 -444
  166. package/front_end/third_party/lighthouse/locales/sl.json +96 -444
  167. package/front_end/third_party/lighthouse/locales/sr-Latn.json +96 -444
  168. package/front_end/third_party/lighthouse/locales/sr.json +96 -444
  169. package/front_end/third_party/lighthouse/locales/sv.json +96 -444
  170. package/front_end/third_party/lighthouse/locales/ta.json +96 -444
  171. package/front_end/third_party/lighthouse/locales/te.json +97 -445
  172. package/front_end/third_party/lighthouse/locales/th.json +96 -444
  173. package/front_end/third_party/lighthouse/locales/tr.json +96 -444
  174. package/front_end/third_party/lighthouse/locales/uk.json +96 -444
  175. package/front_end/third_party/lighthouse/locales/vi.json +96 -444
  176. package/front_end/third_party/lighthouse/locales/zh-HK.json +96 -444
  177. package/front_end/third_party/lighthouse/locales/zh-TW.json +97 -445
  178. package/front_end/third_party/lighthouse/locales/zh.json +96 -444
  179. package/front_end/third_party/lighthouse/report/bundle.d.ts +8 -14
  180. package/front_end/third_party/lighthouse/report/bundle.js +10 -49
  181. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
  182. package/front_end/third_party/web-vitals/README.chromium +5 -8
  183. package/front_end/third_party/web-vitals/package/README.md +191 -152
  184. package/front_end/third_party/web-vitals/package/dist/modules/attribution/index.d.ts +0 -1
  185. package/front_end/third_party/web-vitals/package/dist/modules/attribution/index.js +0 -1
  186. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onCLS.d.ts +2 -2
  187. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onCLS.js +45 -26
  188. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFCP.d.ts +2 -2
  189. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFCP.js +3 -3
  190. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.d.ts +10 -10
  191. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.js +307 -206
  192. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onLCP.d.ts +2 -2
  193. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onLCP.js +69 -49
  194. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onTTFB.d.ts +2 -2
  195. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onTTFB.js +2 -2
  196. package/front_end/third_party/web-vitals/package/dist/modules/index.d.ts +0 -1
  197. package/front_end/third_party/web-vitals/package/dist/modules/index.js +0 -1
  198. package/front_end/third_party/web-vitals/package/dist/modules/lib/InteractionManager.d.ts +33 -0
  199. package/front_end/third_party/web-vitals/package/dist/modules/lib/InteractionManager.js +111 -0
  200. package/front_end/third_party/web-vitals/package/dist/modules/lib/LCPEntryManager.d.ts +4 -0
  201. package/front_end/third_party/web-vitals/package/dist/modules/{attribution/deprecated.js → lib/LCPEntryManager.js} +6 -7
  202. package/front_end/third_party/web-vitals/package/dist/modules/lib/LayoutShiftManager.d.ts +6 -0
  203. package/front_end/third_party/web-vitals/package/dist/modules/lib/LayoutShiftManager.js +44 -0
  204. package/front_end/third_party/web-vitals/package/dist/modules/lib/bindReporter.js +1 -1
  205. package/front_end/third_party/web-vitals/package/dist/modules/lib/generateUniqueID.js +1 -1
  206. package/front_end/third_party/web-vitals/package/dist/modules/lib/getActivationStart.js +1 -1
  207. package/front_end/third_party/web-vitals/package/dist/modules/lib/getNavigationEntry.js +5 -7
  208. package/front_end/third_party/web-vitals/package/dist/modules/lib/getSelector.d.ts +1 -1
  209. package/front_end/third_party/web-vitals/package/dist/modules/lib/getSelector.js +9 -12
  210. package/front_end/third_party/web-vitals/package/dist/modules/lib/getVisibilityWatcher.d.ts +1 -0
  211. package/front_end/third_party/web-vitals/package/dist/modules/lib/getVisibilityWatcher.js +52 -33
  212. package/front_end/third_party/web-vitals/package/dist/modules/lib/initMetric.d.ts +0 -2
  213. package/front_end/third_party/web-vitals/package/dist/modules/lib/initMetric.js +2 -2
  214. package/front_end/third_party/web-vitals/package/dist/modules/lib/initUnique.d.ts +6 -0
  215. package/front_end/third_party/web-vitals/package/dist/modules/{deprecated.js → lib/initUnique.js} +11 -4
  216. package/front_end/third_party/web-vitals/package/dist/modules/lib/observe.js +3 -6
  217. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/interactionCountPolyfill.js +6 -6
  218. package/front_end/third_party/web-vitals/package/dist/modules/lib/{whenIdle.d.ts → whenIdleOrHidden.d.ts} +1 -1
  219. package/front_end/third_party/web-vitals/package/dist/modules/lib/{whenIdle.js → whenIdleOrHidden.js} +10 -8
  220. package/front_end/third_party/web-vitals/package/dist/modules/onCLS.js +17 -35
  221. package/front_end/third_party/web-vitals/package/dist/modules/onFCP.js +3 -5
  222. package/front_end/third_party/web-vitals/package/dist/modules/onINP.d.ts +9 -7
  223. package/front_end/third_party/web-vitals/package/dist/modules/onINP.js +27 -19
  224. package/front_end/third_party/web-vitals/package/dist/modules/onLCP.js +33 -26
  225. package/front_end/third_party/web-vitals/package/dist/modules/onTTFB.js +2 -4
  226. package/front_end/third_party/web-vitals/package/dist/modules/types/base.d.ts +6 -5
  227. package/front_end/third_party/web-vitals/package/dist/modules/types/cls.d.ts +5 -3
  228. package/front_end/third_party/web-vitals/package/dist/modules/types/inp.d.ts +80 -33
  229. package/front_end/third_party/web-vitals/package/dist/modules/types/lcp.d.ts +6 -2
  230. package/front_end/third_party/web-vitals/package/dist/modules/types.d.ts +28 -4
  231. package/front_end/third_party/web-vitals/package/dist/modules/types.js +0 -1
  232. package/front_end/third_party/web-vitals/package/package.json +4 -10
  233. package/front_end/third_party/web-vitals/package/src/attribution/index.ts +0 -1
  234. package/front_end/third_party/web-vitals/package/src/attribution/onCLS.ts +58 -33
  235. package/front_end/third_party/web-vitals/package/src/attribution/onFCP.ts +4 -4
  236. package/front_end/third_party/web-vitals/package/src/attribution/onINP.ts +382 -258
  237. package/front_end/third_party/web-vitals/package/src/attribution/onLCP.ts +96 -69
  238. package/front_end/third_party/web-vitals/package/src/attribution/onTTFB.ts +3 -3
  239. package/front_end/third_party/web-vitals/package/src/index.ts +0 -1
  240. package/front_end/third_party/web-vitals/package/src/lib/InteractionManager.ts +146 -0
  241. package/front_end/third_party/web-vitals/package/src/{attribution/deprecated.ts → lib/LCPEntryManager.ts} +6 -9
  242. package/front_end/third_party/web-vitals/package/src/lib/LayoutShiftManager.ts +50 -0
  243. package/front_end/third_party/web-vitals/package/src/lib/bindReporter.ts +1 -1
  244. package/front_end/third_party/web-vitals/package/src/lib/generateUniqueID.ts +1 -1
  245. package/front_end/third_party/web-vitals/package/src/lib/getActivationStart.ts +1 -1
  246. package/front_end/third_party/web-vitals/package/src/lib/getNavigationEntry.ts +5 -8
  247. package/front_end/third_party/web-vitals/package/src/lib/getSelector.ts +12 -12
  248. package/front_end/third_party/web-vitals/package/src/lib/getVisibilityWatcher.ts +57 -35
  249. package/front_end/third_party/web-vitals/package/src/lib/initMetric.ts +2 -2
  250. package/front_end/third_party/web-vitals/package/src/{deprecated.ts → lib/initUnique.ts} +14 -8
  251. package/front_end/third_party/web-vitals/package/src/lib/observe.ts +3 -11
  252. package/front_end/third_party/web-vitals/package/src/lib/polyfills/interactionCountPolyfill.ts +12 -6
  253. package/front_end/third_party/web-vitals/package/src/lib/{whenIdle.ts → whenIdleOrHidden.ts} +10 -8
  254. package/front_end/third_party/web-vitals/package/src/onCLS.ts +17 -38
  255. package/front_end/third_party/web-vitals/package/src/onFCP.ts +3 -6
  256. package/front_end/third_party/web-vitals/package/src/onINP.ts +33 -28
  257. package/front_end/third_party/web-vitals/package/src/onLCP.ts +36 -29
  258. package/front_end/third_party/web-vitals/package/src/onTTFB.ts +2 -5
  259. package/front_end/third_party/web-vitals/package/src/types/base.ts +5 -5
  260. package/front_end/third_party/web-vitals/package/src/types/cls.ts +5 -3
  261. package/front_end/third_party/web-vitals/package/src/types/inp.ts +88 -33
  262. package/front_end/third_party/web-vitals/package/src/types/lcp.ts +6 -2
  263. package/front_end/third_party/web-vitals/package/src/types.ts +47 -4
  264. package/front_end/third_party/web-vitals/patches/0001-Add-onEachInteraction-to-onINP-options.patch +75 -0
  265. package/front_end/third_party/web-vitals/rebuild.sh +32 -18
  266. package/front_end/third_party/web-vitals/web-vitals-tsconfig.json +5 -10
  267. package/front_end/third_party/web-vitals/web-vitals.ts +0 -2
  268. package/front_end/ui/components/docs/console_insight/basic.ts +3 -2
  269. package/front_end/ui/components/legacy_wrapper/LegacyWrapper.ts +2 -0
  270. package/front_end/ui/components/text_editor/TextEditor.ts +0 -2
  271. package/front_end/ui/legacy/InspectorView.ts +2 -0
  272. package/front_end/ui/legacy/SplitWidget.ts +2 -0
  273. package/front_end/ui/legacy/TabbedPane.ts +1 -0
  274. package/front_end/ui/legacy/TargetCrashedScreen.ts +1 -0
  275. package/front_end/ui/legacy/UIUtils.ts +8 -19
  276. package/front_end/ui/legacy/ViewManager.ts +1 -0
  277. package/front_end/ui/legacy/components/color_picker/FormatPickerContextMenu.ts +7 -20
  278. package/front_end/ui/legacy/components/color_picker/Spectrum.ts +2 -0
  279. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +1 -0
  280. package/front_end/ui/legacy/components/inline_editor/BezierEditor.ts +1 -0
  281. package/front_end/ui/legacy/components/perf_ui/ChartViewport.ts +1 -0
  282. package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +1 -0
  283. package/front_end/ui/legacy/components/source_frame/FontView.ts +1 -0
  284. package/front_end/ui/legacy/components/source_frame/ImageView.ts +1 -0
  285. package/front_end/ui/legacy/components/source_frame/JSONView.ts +1 -0
  286. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +1 -0
  287. package/front_end/ui/legacy/components/source_frame/StreamingContentHexView.ts +2 -0
  288. package/front_end/ui/visual_logging/KnownContextValues.ts +17 -0
  289. package/mcp/README.md +7 -0
  290. package/mcp/mcp.ts +8 -0
  291. package/package.json +1 -1
  292. package/front_end/models/live-metrics/web-vitals-injected/OnEachInteraction.ts +0 -34
  293. package/front_end/third_party/web-vitals/package/attribution.d.ts +0 -16
  294. package/front_end/third_party/web-vitals/package/attribution.js +0 -18
  295. package/front_end/third_party/web-vitals/package/dist/modules/attribution/deprecated.d.ts +0 -7
  296. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFID.d.ts +0 -11
  297. package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFID.js +0 -46
  298. package/front_end/third_party/web-vitals/package/dist/modules/deprecated.d.ts +0 -5
  299. package/front_end/third_party/web-vitals/package/dist/modules/lib/interactions.d.ts +0 -31
  300. package/front_end/third_party/web-vitals/package/dist/modules/lib/interactions.js +0 -107
  301. package/front_end/third_party/web-vitals/package/dist/modules/lib/onHidden.d.ts +0 -1
  302. package/front_end/third_party/web-vitals/package/dist/modules/lib/onHidden.js +0 -22
  303. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/firstInputPolyfill.d.ts +0 -7
  304. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/firstInputPolyfill.js +0 -147
  305. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/getFirstHiddenTimePolyfill.d.ts +0 -1
  306. package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/getFirstHiddenTimePolyfill.js +0 -25
  307. package/front_end/third_party/web-vitals/package/dist/modules/onFID.d.ts +0 -13
  308. package/front_end/third_party/web-vitals/package/dist/modules/onFID.js +0 -70
  309. package/front_end/third_party/web-vitals/package/dist/modules/types/fid.d.ts +0 -46
  310. package/front_end/third_party/web-vitals/package/dist/modules/types/fid.js +0 -16
  311. package/front_end/third_party/web-vitals/package/src/attribution/onFID.ts +0 -62
  312. package/front_end/third_party/web-vitals/package/src/lib/interactions.ts +0 -139
  313. package/front_end/third_party/web-vitals/package/src/lib/onHidden.ts +0 -23
  314. package/front_end/third_party/web-vitals/package/src/lib/polyfills/firstInputPolyfill.ts +0 -174
  315. package/front_end/third_party/web-vitals/package/src/onFID.ts +0 -105
  316. package/front_end/third_party/web-vitals/package/src/types/fid.ts +0 -65
  317. package/front_end/ui/components/text_editor/textEditor.css +0 -18
  318. package/front_end/ui/legacy/inlineButton.css +0 -22
  319. /package/front_end/entrypoints/{rehydrated_devtools_app/rehydrated_devtools_app.ts → trace_app/trace_app.ts} +0 -0
@@ -16,81 +16,16 @@
16
16
 
17
17
  import {getNavigationEntry} from '../lib/getNavigationEntry.js';
18
18
  import {getSelector} from '../lib/getSelector.js';
19
+ import {initUnique} from '../lib/initUnique.js';
20
+ import {LCPEntryManager} from '../lib/LCPEntryManager.js';
19
21
  import {onLCP as unattributedOnLCP} from '../onLCP.js';
20
22
  import {
21
23
  LCPAttribution,
22
24
  LCPMetric,
23
25
  LCPMetricWithAttribution,
24
- ReportOpts,
26
+ AttributionReportOpts,
25
27
  } from '../types.js';
26
28
 
27
- const attributeLCP = (metric: LCPMetric): LCPMetricWithAttribution => {
28
- // Use a default object if no other attribution has been set.
29
- let attribution: LCPAttribution = {
30
- timeToFirstByte: 0,
31
- resourceLoadDelay: 0,
32
- resourceLoadDuration: 0,
33
- elementRenderDelay: metric.value,
34
- };
35
-
36
- if (metric.entries.length) {
37
- const navigationEntry = getNavigationEntry();
38
- if (navigationEntry) {
39
- const activationStart = navigationEntry.activationStart || 0;
40
- const lcpEntry = metric.entries[metric.entries.length - 1];
41
- const lcpResourceEntry =
42
- lcpEntry.url &&
43
- performance
44
- .getEntriesByType('resource')
45
- .filter((e) => e.name === lcpEntry.url)[0];
46
-
47
- const ttfb = Math.max(0, navigationEntry.responseStart - activationStart);
48
-
49
- const lcpRequestStart = Math.max(
50
- ttfb,
51
- // Prefer `requestStart` (if TOA is set), otherwise use `startTime`.
52
- lcpResourceEntry
53
- ? (lcpResourceEntry.requestStart || lcpResourceEntry.startTime) -
54
- activationStart
55
- : 0,
56
- );
57
- const lcpResponseEnd = Math.max(
58
- lcpRequestStart,
59
- lcpResourceEntry ? lcpResourceEntry.responseEnd - activationStart : 0,
60
- );
61
- const lcpRenderTime = Math.max(
62
- lcpResponseEnd,
63
- lcpEntry.startTime - activationStart,
64
- );
65
-
66
- attribution = {
67
- element: getSelector(lcpEntry.element),
68
- timeToFirstByte: ttfb,
69
- resourceLoadDelay: lcpRequestStart - ttfb,
70
- resourceLoadDuration: lcpResponseEnd - lcpRequestStart,
71
- elementRenderDelay: lcpRenderTime - lcpResponseEnd,
72
- navigationEntry,
73
- lcpEntry,
74
- };
75
-
76
- // Only attribution the URL and resource entry if they exist.
77
- if (lcpEntry.url) {
78
- attribution.url = lcpEntry.url;
79
- }
80
- if (lcpResourceEntry) {
81
- attribution.lcpResourceEntry = lcpResourceEntry;
82
- }
83
- }
84
- }
85
-
86
- // Use Object.assign to set property to keep tsc happy.
87
- const metricWithAttribution: LCPMetricWithAttribution = Object.assign(
88
- metric,
89
- {attribution},
90
- );
91
- return metricWithAttribution;
92
- };
93
-
94
29
  /**
95
30
  * Calculates the [LCP](https://web.dev/articles/lcp) value for the current page and
96
31
  * calls the `callback` function once the value is ready (along with the
@@ -104,8 +39,100 @@ const attributeLCP = (metric: LCPMetric): LCPMetricWithAttribution => {
104
39
  */
105
40
  export const onLCP = (
106
41
  onReport: (metric: LCPMetricWithAttribution) => void,
107
- opts?: ReportOpts,
42
+ opts: AttributionReportOpts = {},
108
43
  ) => {
44
+ // Clone the opts object to ensure it's unique, so we can initialize a
45
+ // single instance of the `LCPEntryManager` class that's shared only with
46
+ // this function invocation and the `unattributedOnLCP()` invocation below
47
+ // (which is passed the same `opts` object).
48
+ opts = Object.assign({}, opts);
49
+
50
+ const lcpEntryManager = initUnique(opts, LCPEntryManager);
51
+ const lcpTargetMap: WeakMap<LargestContentfulPaint, string> = new WeakMap();
52
+
53
+ lcpEntryManager._onBeforeProcessingEntry = (
54
+ entry: LargestContentfulPaint,
55
+ ) => {
56
+ const node = entry.element;
57
+ if (node) {
58
+ const customTarget = opts.generateTarget?.(node) ?? getSelector(node);
59
+ lcpTargetMap.set(entry, customTarget);
60
+ }
61
+ };
62
+
63
+ const attributeLCP = (metric: LCPMetric): LCPMetricWithAttribution => {
64
+ // Use a default object if no other attribution has been set.
65
+ let attribution: LCPAttribution = {
66
+ timeToFirstByte: 0,
67
+ resourceLoadDelay: 0,
68
+ resourceLoadDuration: 0,
69
+ elementRenderDelay: metric.value,
70
+ };
71
+
72
+ if (metric.entries.length) {
73
+ const navigationEntry = getNavigationEntry();
74
+ if (navigationEntry) {
75
+ const activationStart = navigationEntry.activationStart || 0;
76
+ // The `metric.entries.length` check ensures there will be an entry.
77
+ const lcpEntry = metric.entries.at(-1)!;
78
+ const lcpResourceEntry =
79
+ lcpEntry.url &&
80
+ performance
81
+ .getEntriesByType('resource')
82
+ .filter((e) => e.name === lcpEntry.url)[0];
83
+
84
+ const ttfb = Math.max(
85
+ 0,
86
+ navigationEntry.responseStart - activationStart,
87
+ );
88
+
89
+ const lcpRequestStart = Math.max(
90
+ ttfb,
91
+ // Prefer `requestStart` (if TOA is set), otherwise use `startTime`.
92
+ lcpResourceEntry
93
+ ? (lcpResourceEntry.requestStart || lcpResourceEntry.startTime) -
94
+ activationStart
95
+ : 0,
96
+ );
97
+ const lcpResponseEnd = Math.min(
98
+ // Cap at LCP time (videos continue downloading after LCP for example)
99
+ metric.value,
100
+ Math.max(
101
+ lcpRequestStart,
102
+ lcpResourceEntry
103
+ ? lcpResourceEntry.responseEnd - activationStart
104
+ : 0,
105
+ ),
106
+ );
107
+
108
+ attribution = {
109
+ target: lcpTargetMap.get(lcpEntry),
110
+ timeToFirstByte: ttfb,
111
+ resourceLoadDelay: lcpRequestStart - ttfb,
112
+ resourceLoadDuration: lcpResponseEnd - lcpRequestStart,
113
+ elementRenderDelay: metric.value - lcpResponseEnd,
114
+ navigationEntry,
115
+ lcpEntry,
116
+ };
117
+
118
+ // Only attribute the URL and resource entry if they exist.
119
+ if (lcpEntry.url) {
120
+ attribution.url = lcpEntry.url;
121
+ }
122
+ if (lcpResourceEntry) {
123
+ attribution.lcpResourceEntry = lcpResourceEntry;
124
+ }
125
+ }
126
+ }
127
+
128
+ // Use `Object.assign()` to ensure the original metric object is returned.
129
+ const metricWithAttribution: LCPMetricWithAttribution = Object.assign(
130
+ metric,
131
+ {attribution},
132
+ );
133
+ return metricWithAttribution;
134
+ };
135
+
109
136
  unattributedOnLCP((metric: LCPMetric) => {
110
137
  const metricWithAttribution = attributeLCP(metric);
111
138
  onReport(metricWithAttribution);
@@ -18,7 +18,7 @@ import {onTTFB as unattributedOnTTFB} from '../onTTFB.js';
18
18
  import {
19
19
  TTFBMetric,
20
20
  TTFBMetricWithAttribution,
21
- ReportOpts,
21
+ AttributionReportOpts,
22
22
  TTFBAttribution,
23
23
  } from '../types.js';
24
24
 
@@ -73,7 +73,7 @@ const attributeTTFB = (metric: TTFBMetric): TTFBMetricWithAttribution => {
73
73
  };
74
74
  }
75
75
 
76
- // Use Object.assign to set property to keep tsc happy.
76
+ // Use `Object.assign()` to ensure the original metric object is returned.
77
77
  const metricWithAttribution: TTFBMetricWithAttribution = Object.assign(
78
78
  metric,
79
79
  {attribution},
@@ -98,7 +98,7 @@ const attributeTTFB = (metric: TTFBMetric): TTFBMetricWithAttribution => {
98
98
  */
99
99
  export const onTTFB = (
100
100
  onReport: (metric: TTFBMetricWithAttribution) => void,
101
- opts?: ReportOpts,
101
+ opts: AttributionReportOpts = {},
102
102
  ) => {
103
103
  unattributedOnTTFB((metric: TTFBMetric) => {
104
104
  const metricWithAttribution = attributeTTFB(metric);
@@ -20,5 +20,4 @@ export {onINP, INPThresholds} from './onINP.js';
20
20
  export {onLCP, LCPThresholds} from './onLCP.js';
21
21
  export {onTTFB, TTFBThresholds} from './onTTFB.js';
22
22
 
23
- export * from './deprecated.js';
24
23
  export * from './types.js';
@@ -0,0 +1,146 @@
1
+ /*
2
+ * Copyright 2024 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {getInteractionCount} from './polyfills/interactionCountPolyfill.js';
18
+
19
+ export interface Interaction {
20
+ _latency: number;
21
+ // While the `id` and `entries` properties are also internal and could be
22
+ // mangled by prefixing with an underscore, since they correspond to public
23
+ // symbols there is no need to mangle them as the library will compress
24
+ // better if we reuse the existing names.
25
+ id: number;
26
+ entries: PerformanceEventTiming[];
27
+ }
28
+
29
+ // To prevent unnecessary memory usage on pages with lots of interactions,
30
+ // store at most 10 of the longest interactions to consider as INP candidates.
31
+ const MAX_INTERACTIONS_TO_CONSIDER = 10;
32
+
33
+ // Used to store the interaction count after a bfcache restore, since p98
34
+ // interaction latencies should only consider the current navigation.
35
+ let prevInteractionCount = 0;
36
+
37
+ /**
38
+ * Returns the interaction count since the last bfcache restore (or for the
39
+ * full page lifecycle if there were no bfcache restores).
40
+ */
41
+ const getInteractionCountForNavigation = () => {
42
+ return getInteractionCount() - prevInteractionCount;
43
+ };
44
+
45
+ export class InteractionManager {
46
+ /**
47
+ * A list of longest interactions on the page (by latency) sorted so the
48
+ * longest one is first. The list is at most MAX_INTERACTIONS_TO_CONSIDER
49
+ * long.
50
+ */
51
+ _longestInteractionList: Interaction[] = [];
52
+
53
+ /**
54
+ * A mapping of longest interactions by their interaction ID.
55
+ * This is used for faster lookup.
56
+ */
57
+ _longestInteractionMap: Map<number, Interaction> = new Map();
58
+
59
+ _onBeforeProcessingEntry?: (entry: PerformanceEventTiming) => void;
60
+
61
+ _onAfterProcessingINPCandidate?: (interaction: Interaction) => void;
62
+
63
+ _resetInteractions() {
64
+ prevInteractionCount = getInteractionCount();
65
+ this._longestInteractionList.length = 0;
66
+ this._longestInteractionMap.clear();
67
+ }
68
+
69
+ /**
70
+ * Returns the estimated p98 longest interaction based on the stored
71
+ * interaction candidates and the interaction count for the current page.
72
+ */
73
+ _estimateP98LongestInteraction() {
74
+ const candidateInteractionIndex = Math.min(
75
+ this._longestInteractionList.length - 1,
76
+ Math.floor(getInteractionCountForNavigation() / 50),
77
+ );
78
+
79
+ return this._longestInteractionList[candidateInteractionIndex];
80
+ }
81
+
82
+ /**
83
+ * Takes a performance entry and adds it to the list of worst interactions
84
+ * if its duration is long enough to make it among the worst. If the
85
+ * entry is part of an existing interaction, it is merged and the latency
86
+ * and entries list is updated as needed.
87
+ */
88
+ _processEntry(entry: PerformanceEventTiming) {
89
+ this._onBeforeProcessingEntry?.(entry);
90
+
91
+ // Skip further processing for entries that cannot be INP candidates.
92
+ if (!(entry.interactionId || entry.entryType === 'first-input')) return;
93
+
94
+ // The least-long of the 10 longest interactions.
95
+ const minLongestInteraction = this._longestInteractionList.at(-1);
96
+
97
+ let interaction = this._longestInteractionMap.get(entry.interactionId!);
98
+
99
+ // Only process the entry if it's possibly one of the ten longest,
100
+ // or if it's part of an existing interaction.
101
+ if (
102
+ interaction ||
103
+ this._longestInteractionList.length < MAX_INTERACTIONS_TO_CONSIDER ||
104
+ // If the above conditions are false, `minLongestInteraction` will be set.
105
+ entry.duration > minLongestInteraction!._latency
106
+ ) {
107
+ // If the interaction already exists, update it. Otherwise create one.
108
+ if (interaction) {
109
+ // If the new entry has a longer duration, replace the old entries,
110
+ // otherwise add to the array.
111
+ if (entry.duration > interaction._latency) {
112
+ interaction.entries = [entry];
113
+ interaction._latency = entry.duration;
114
+ } else if (
115
+ entry.duration === interaction._latency &&
116
+ entry.startTime === interaction.entries[0].startTime
117
+ ) {
118
+ interaction.entries.push(entry);
119
+ }
120
+ } else {
121
+ interaction = {
122
+ id: entry.interactionId!,
123
+ entries: [entry],
124
+ _latency: entry.duration,
125
+ };
126
+ this._longestInteractionMap.set(interaction.id, interaction);
127
+ this._longestInteractionList.push(interaction);
128
+ }
129
+
130
+ // Sort the entries by latency (descending) and keep only the top ten.
131
+ this._longestInteractionList.sort((a, b) => b._latency - a._latency);
132
+ if (this._longestInteractionList.length > MAX_INTERACTIONS_TO_CONSIDER) {
133
+ const removedInteractions = this._longestInteractionList.splice(
134
+ MAX_INTERACTIONS_TO_CONSIDER,
135
+ );
136
+
137
+ for (const interaction of removedInteractions) {
138
+ this._longestInteractionMap.delete(interaction.id);
139
+ }
140
+ }
141
+
142
+ // Call any post-processing on the interaction
143
+ this._onAfterProcessingINPCandidate?.(interaction);
144
+ }
145
+ }
146
+ }
@@ -14,13 +14,10 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- export {
18
- /**
19
- * @deprecated Use `onINP()` instead.
20
- */
21
- onFID,
22
- } from './onFID.js';
17
+ export class LCPEntryManager {
18
+ _onBeforeProcessingEntry?: (entry: LargestContentfulPaint) => void;
23
19
 
24
- export {FIDThresholds} from '../onFID.js';
25
-
26
- export * from '../types.js';
20
+ _processEntry(entry: LargestContentfulPaint) {
21
+ this._onBeforeProcessingEntry?.(entry);
22
+ }
23
+ }
@@ -0,0 +1,50 @@
1
+ /*
2
+ * Copyright 2024 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ export class LayoutShiftManager {
18
+ _onAfterProcessingUnexpectedShift?: (entry: LayoutShift) => void;
19
+
20
+ _sessionValue = 0;
21
+ _sessionEntries: LayoutShift[] = [];
22
+
23
+ _processEntry(entry: LayoutShift) {
24
+ // Only count layout shifts without recent user input.
25
+ if (entry.hadRecentInput) return;
26
+
27
+ const firstSessionEntry = this._sessionEntries[0];
28
+ const lastSessionEntry = this._sessionEntries.at(-1);
29
+
30
+ // If the entry occurred less than 1 second after the previous entry
31
+ // and less than 5 seconds after the first entry in the session,
32
+ // include the entry in the current session. Otherwise, start a new
33
+ // session.
34
+ if (
35
+ this._sessionValue &&
36
+ firstSessionEntry &&
37
+ lastSessionEntry &&
38
+ entry.startTime - lastSessionEntry.startTime < 1000 &&
39
+ entry.startTime - firstSessionEntry.startTime < 5000
40
+ ) {
41
+ this._sessionValue += entry.value;
42
+ this._sessionEntries.push(entry);
43
+ } else {
44
+ this._sessionValue = entry.value;
45
+ this._sessionEntries = [entry];
46
+ }
47
+
48
+ this._onAfterProcessingUnexpectedShift?.(entry);
49
+ }
50
+ }
@@ -40,7 +40,7 @@ export const bindReporter = <MetricName extends MetricType['name']>(
40
40
  return (forceReport?: boolean) => {
41
41
  if (metric.value >= 0) {
42
42
  if (forceReport || reportAllChanges) {
43
- delta = metric.value - (prevValue || 0);
43
+ delta = metric.value - (prevValue ?? 0);
44
44
 
45
45
  // Report the metric if there's a non-zero delta or if no previous
46
46
  // value exists (which can happen in the case of the document becoming
@@ -20,5 +20,5 @@
20
20
  * @return {string}
21
21
  */
22
22
  export const generateUniqueID = () => {
23
- return `v4-${Date.now()}-${Math.floor(Math.random() * (9e12 - 1)) + 1e12}`;
23
+ return `v5-${Date.now()}-${Math.floor(Math.random() * (9e12 - 1)) + 1e12}`;
24
24
  };
@@ -18,5 +18,5 @@ import {getNavigationEntry} from './getNavigationEntry.js';
18
18
 
19
19
  export const getActivationStart = (): number => {
20
20
  const navEntry = getNavigationEntry();
21
- return (navEntry && navEntry.activationStart) || 0;
21
+ return navEntry?.activationStart ?? 0;
22
22
  };
@@ -15,18 +15,15 @@
15
15
  */
16
16
 
17
17
  export const getNavigationEntry = (): PerformanceNavigationTiming | void => {
18
- const navigationEntry =
19
- self.performance &&
20
- performance.getEntriesByType &&
21
- performance.getEntriesByType('navigation')[0];
18
+ const navigationEntry = performance.getEntriesByType('navigation')[0];
22
19
 
23
20
  // Check to ensure the `responseStart` property is present and valid.
24
- // In some cases no value is reported by the browser (for
21
+ // In some cases a zero value is reported by the browser (for
25
22
  // privacy/security reasons), and in other cases (bugs) the value is
26
23
  // negative or is larger than the current page time. Ignore these cases:
27
- // https://github.com/GoogleChrome/web-vitals/issues/137
28
- // https://github.com/GoogleChrome/web-vitals/issues/162
29
- // https://github.com/GoogleChrome/web-vitals/issues/275
24
+ // - https://github.com/GoogleChrome/web-vitals/issues/137
25
+ // - https://github.com/GoogleChrome/web-vitals/issues/162
26
+ // - https://github.com/GoogleChrome/web-vitals/issues/275
30
27
  if (
31
28
  navigationEntry &&
32
29
  navigationEntry.responseStart > 0 &&
@@ -21,27 +21,27 @@ const getName = (node: Node) => {
21
21
  : name.toUpperCase().replace(/^#/, '');
22
22
  };
23
23
 
24
- export const getSelector = (node: Node | null | undefined, maxLen?: number) => {
24
+ const MAX_LEN = 100;
25
+
26
+ export const getSelector = (node: Node | null) => {
25
27
  let sel = '';
26
28
 
27
29
  try {
28
- while (node && node.nodeType !== 9) {
30
+ while (node?.nodeType !== 9) {
29
31
  const el: Element = node as Element;
30
32
  const part = el.id
31
33
  ? '#' + el.id
32
- : getName(el) +
33
- (el.classList &&
34
- el.classList.value &&
35
- el.classList.value.trim() &&
36
- el.classList.value.trim().length
37
- ? '.' + el.classList.value.trim().replace(/\s+/g, '.')
38
- : '');
39
- if (sel.length + part.length > (maxLen || 100) - 1) return sel || part;
34
+ : [getName(el), ...Array.from(el.classList).sort()].join('.');
35
+ if (sel.length + part.length > MAX_LEN - 1) {
36
+ return sel || part;
37
+ }
40
38
  sel = sel ? part + '>' + sel : part;
41
- if (el.id) break;
39
+ if (el.id) {
40
+ break;
41
+ }
42
42
  node = el.parentNode;
43
43
  }
44
- } catch (err) {
44
+ } catch {
45
45
  // Do nothing...
46
46
  }
47
47
  return sel;
@@ -15,8 +15,10 @@
15
15
  */
16
16
 
17
17
  import {onBFCacheRestore} from './bfcache.js';
18
+ import {getActivationStart} from './getActivationStart.js';
18
19
 
19
20
  let firstHiddenTime = -1;
21
+ const onHiddenFunctions: Set<() => void> = new Set();
20
22
 
21
23
  const initHiddenTime = () => {
22
24
  // If the document is hidden when this code runs, assume it was always
@@ -30,45 +32,63 @@ const initHiddenTime = () => {
30
32
  };
31
33
 
32
34
  const onVisibilityUpdate = (event: Event) => {
33
- // If the document is 'hidden' and no previous hidden timestamp has been
34
- // set, update it based on the current event data.
35
- if (document.visibilityState === 'hidden' && firstHiddenTime > -1) {
36
- // If the event is a 'visibilitychange' event, it means the page was
37
- // visible prior to this change, so the event timestamp is the first
38
- // hidden time.
39
- // However, if the event is not a 'visibilitychange' event, then it must
40
- // be a 'prerenderingchange' event, and the fact that the document is
41
- // still 'hidden' from the above check means the tab was activated
42
- // in a background state and so has always been hidden.
43
- firstHiddenTime = event.type === 'visibilitychange' ? event.timeStamp : 0;
35
+ // Handle changes to hidden state
36
+ if (document.visibilityState === 'hidden') {
37
+ if (event.type === 'visibilitychange') {
38
+ for (const onHiddenFunction of onHiddenFunctions) {
39
+ onHiddenFunction();
40
+ }
41
+ }
44
42
 
45
- // Remove all listeners now that a `firstHiddenTime` value has been set.
46
- removeChangeListeners();
47
- }
48
- };
49
-
50
- const addChangeListeners = () => {
51
- addEventListener('visibilitychange', onVisibilityUpdate, true);
52
- // IMPORTANT: when a page is prerendering, its `visibilityState` is
53
- // 'hidden', so in order to account for cases where this module checks for
54
- // visibility during prerendering, an additional check after prerendering
55
- // completes is also required.
56
- addEventListener('prerenderingchange', onVisibilityUpdate, true);
57
- };
43
+ // If the document is 'hidden' and no previous hidden timestamp has been
44
+ // set (so is infinity), update it based on the current event data.
45
+ if (!isFinite(firstHiddenTime)) {
46
+ // If the event is a 'visibilitychange' event, it means the page was
47
+ // visible prior to this change, so the event timestamp is the first
48
+ // hidden time.
49
+ // However, if the event is not a 'visibilitychange' event, then it must
50
+ // be a 'prerenderingchange' event, and the fact that the document is
51
+ // still 'hidden' from the above check means the tab was activated
52
+ // in a background state and so has always been hidden.
53
+ firstHiddenTime = event.type === 'visibilitychange' ? event.timeStamp : 0;
58
54
 
59
- const removeChangeListeners = () => {
60
- removeEventListener('visibilitychange', onVisibilityUpdate, true);
61
- removeEventListener('prerenderingchange', onVisibilityUpdate, true);
55
+ // We no longer need the `prerenderingchange` event listener now we've
56
+ // set an initial init time so remove that
57
+ // (we'll keep the visibilitychange one for onHiddenFunction above)
58
+ removeEventListener('prerenderingchange', onVisibilityUpdate, true);
59
+ }
60
+ }
62
61
  };
63
62
 
64
63
  export const getVisibilityWatcher = () => {
65
64
  if (firstHiddenTime < 0) {
66
- // If the document is hidden when this code runs, assume it was hidden
67
- // since navigation start. This isn't a perfect heuristic, but it's the
68
- // best we can do until an API is available to support querying past
69
- // visibilityState.
70
- firstHiddenTime = initHiddenTime();
71
- addChangeListeners();
65
+ // Check if we have a previous hidden `visibility-state` performance entry.
66
+ const activationStart = getActivationStart();
67
+ /* eslint-disable indent */
68
+ const firstVisibilityStateHiddenTime = !document.prerendering
69
+ ? globalThis.performance
70
+ .getEntriesByType('visibility-state')
71
+ .filter(
72
+ (e) => e.name === 'hidden' && e.startTime > activationStart,
73
+ )[0]?.startTime
74
+ : undefined;
75
+ /* eslint-enable indent */
76
+
77
+ // Prefer that, but if it's not available and the document is hidden when
78
+ // this code runs, assume it was hidden since navigation start. This isn't
79
+ // a perfect heuristic, but it's the best we can do until the
80
+ // `visibility-state` performance entry becomes available in all browsers.
81
+ firstHiddenTime = firstVisibilityStateHiddenTime ?? initHiddenTime();
82
+
83
+ // Listen for visibility changes so we can handle things like bfcache
84
+ // restores and/or prerender without having to examine individual
85
+ // timestamps in detail and also for onHidden function calls.
86
+ addEventListener('visibilitychange', onVisibilityUpdate, true);
87
+ // IMPORTANT: when a page is prerendering, its `visibilityState` is
88
+ // 'hidden', so in order to account for cases where this module checks for
89
+ // visibility during prerendering, an additional check after prerendering
90
+ // completes is also required.
91
+ addEventListener('prerenderingchange', onVisibilityUpdate, true);
72
92
 
73
93
  // Reset the time on bfcache restores.
74
94
  onBFCacheRestore(() => {
@@ -77,13 +97,15 @@ export const getVisibilityWatcher = () => {
77
97
  // https://bugs.chromium.org/p/chromium/issues/detail?id=1133363
78
98
  setTimeout(() => {
79
99
  firstHiddenTime = initHiddenTime();
80
- addChangeListeners();
81
- }, 0);
100
+ });
82
101
  });
83
102
  }
84
103
  return {
85
104
  get firstHiddenTime() {
86
105
  return firstHiddenTime;
87
106
  },
107
+ onHidden(cb: () => void) {
108
+ onHiddenFunctions.add(cb);
109
+ },
88
110
  };
89
111
  };