browser-debugger-cli 0.8.0 → 0.10.0

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 (304) hide show
  1. package/README.md +7 -1
  2. package/dist/cdp/schema.d.ts +4 -1
  3. package/dist/cdp/schema.js +48 -7
  4. package/dist/commands/cdp.js +3 -2
  5. package/dist/commands/cleanup.d.ts +11 -0
  6. package/dist/commands/cleanup.js +161 -57
  7. package/dist/commands/console.d.ts +20 -1
  8. package/dist/commands/console.js +57 -17
  9. package/dist/commands/details.js +3 -2
  10. package/dist/commands/dom/DomElementResolver.d.ts +10 -3
  11. package/dist/commands/dom/DomElementResolver.js +35 -17
  12. package/dist/commands/dom/a11y.d.ts +10 -0
  13. package/dist/commands/dom/a11y.js +29 -6
  14. package/dist/commands/dom/eval.d.ts +3 -1
  15. package/dist/commands/dom/eval.js +29 -4
  16. package/dist/commands/dom/form.js +16 -62
  17. package/dist/commands/dom/formInteraction.js +189 -119
  18. package/dist/commands/dom/formSummary.d.ts +49 -0
  19. package/dist/commands/dom/formSummary.js +180 -0
  20. package/dist/commands/dom/frames.d.ts +2 -1
  21. package/dist/commands/dom/frames.js +17 -2
  22. package/dist/commands/dom/get.d.ts +6 -5
  23. package/dist/commands/dom/get.js +92 -82
  24. package/dist/commands/dom/helpers/index.d.ts +1 -1
  25. package/dist/commands/dom/helpers/index.js +1 -1
  26. package/dist/commands/dom/helpers/keyAttributes.d.ts +20 -0
  27. package/dist/commands/dom/helpers/keyAttributes.js +54 -0
  28. package/dist/commands/dom/helpers/query.d.ts +44 -17
  29. package/dist/commands/dom/helpers/query.js +300 -106
  30. package/dist/commands/dom/helpers/runElementCommand.d.ts +10 -2
  31. package/dist/commands/dom/helpers/runElementCommand.js +98 -30
  32. package/dist/commands/dom/helpers/screenshot.d.ts +4 -1
  33. package/dist/commands/dom/helpers/screenshot.js +239 -51
  34. package/dist/commands/dom/index.d.ts +4 -1
  35. package/dist/commands/dom/index.js +22 -7
  36. package/dist/commands/dom/inspect.d.ts +15 -0
  37. package/dist/commands/dom/inspect.js +82 -0
  38. package/dist/commands/dom/layout.d.ts +14 -0
  39. package/dist/commands/dom/layout.js +54 -0
  40. package/dist/commands/dom/listeners.d.ts +5 -1
  41. package/dist/commands/dom/listeners.js +15 -5
  42. package/dist/commands/dom/query.js +2 -3
  43. package/dist/commands/dom/screenshot.d.ts +12 -2
  44. package/dist/commands/dom/screenshot.js +27 -3
  45. package/dist/commands/dom/semanticUtils.d.ts +16 -10
  46. package/dist/commands/dom/semanticUtils.js +53 -16
  47. package/dist/commands/dom/wait.d.ts +13 -0
  48. package/dist/commands/dom/wait.js +83 -0
  49. package/dist/commands/helpJson.js +2 -2
  50. package/dist/commands/network/list.js +17 -13
  51. package/dist/commands/optionBehaviors.js +154 -21
  52. package/dist/commands/page.d.ts +3 -2
  53. package/dist/commands/page.js +100 -5
  54. package/dist/commands/peek.js +4 -11
  55. package/dist/commands/sessions.d.ts +8 -0
  56. package/dist/commands/sessions.js +19 -0
  57. package/dist/commands/shared/CommandRunner.js +4 -4
  58. package/dist/commands/shared/commonOptions.d.ts +4 -0
  59. package/dist/commands/shared/commonOptions.js +9 -0
  60. package/dist/commands/shared/dataFetcher.js +2 -2
  61. package/dist/commands/shared/followMode.d.ts +21 -1
  62. package/dist/commands/shared/followMode.js +29 -2
  63. package/dist/commands/shared/handleValidationError.d.ts +2 -2
  64. package/dist/commands/shared/handleValidationError.js +12 -3
  65. package/dist/commands/shared/optionTypes.d.ts +61 -5
  66. package/dist/commands/shared/startHelpers.d.ts +66 -0
  67. package/dist/commands/shared/startHelpers.js +103 -13
  68. package/dist/commands/shared/validation.d.ts +14 -2
  69. package/dist/commands/shared/validation.js +20 -3
  70. package/dist/commands/start.d.ts +63 -0
  71. package/dist/commands/start.js +115 -15
  72. package/dist/commands/status.js +29 -7
  73. package/dist/commands/stop.js +7 -6
  74. package/dist/commands/tail.js +4 -11
  75. package/dist/commands/types.d.ts +2 -0
  76. package/dist/commands.js +2 -0
  77. package/dist/connection/chromeIdentity.d.ts +65 -0
  78. package/dist/connection/chromeIdentity.js +143 -0
  79. package/dist/connection/launcher/profilePreferences.d.ts +47 -0
  80. package/dist/connection/launcher/profilePreferences.js +151 -0
  81. package/dist/connection/launcher.d.ts +21 -2
  82. package/dist/connection/launcher.js +42 -16
  83. package/dist/connection/portReservation.d.ts +14 -4
  84. package/dist/connection/portReservation.js +21 -6
  85. package/dist/connection/startupExit.d.ts +8 -0
  86. package/dist/connection/startupExit.js +15 -6
  87. package/dist/constants.d.ts +6 -2
  88. package/dist/constants.js +9 -2
  89. package/dist/daemon/SessionController.js +23 -7
  90. package/dist/daemon/errors.d.ts +1 -1
  91. package/dist/daemon/errors.js +1 -1
  92. package/dist/daemon/launcher.d.ts +10 -2
  93. package/dist/daemon/launcher.js +8 -7
  94. package/dist/daemon/server/SocketServer.js +1 -2
  95. package/dist/daemon/session/Session.d.ts +20 -0
  96. package/dist/daemon/session/Session.js +80 -9
  97. package/dist/daemon/session/chromeConnection.d.ts +9 -0
  98. package/dist/daemon/session/chromeConnection.js +45 -8
  99. package/dist/daemon/session/commandRegistry.d.ts +14 -1
  100. package/dist/daemon/session/commandRegistry.js +113 -67
  101. package/dist/daemon/session/interactions.d.ts +48 -9
  102. package/dist/daemon/session/interactions.js +46 -9
  103. package/dist/daemon/session/triggeredRequests.d.ts +67 -0
  104. package/dist/daemon/session/triggeredRequests.js +157 -0
  105. package/dist/daemon/session/types.d.ts +5 -1
  106. package/dist/daemon.js +10630 -3601
  107. package/dist/errors/messages.d.ts +456 -24
  108. package/dist/errors/messages.js +862 -67
  109. package/dist/index.js +6915 -3401
  110. package/dist/ipc/client.d.ts +21 -1
  111. package/dist/ipc/client.js +35 -3
  112. package/dist/ipc/protocol/commands.d.ts +145 -5
  113. package/dist/ipc/protocol/commands.js +4 -0
  114. package/dist/ipc/protocol/domTypes.d.ts +291 -7
  115. package/dist/ipc/protocol/inspectTypes.d.ts +388 -0
  116. package/dist/ipc/protocol/inspectTypes.js +10 -0
  117. package/dist/ipc/session/lifecycle.d.ts +8 -1
  118. package/dist/ipc/session/queries.d.ts +5 -1
  119. package/dist/ipc/session/types.d.ts +5 -0
  120. package/dist/ipc/transport/index.d.ts +2 -1
  121. package/dist/ipc/transport/index.js +2 -2
  122. package/dist/runtime/dom/actionEffects.d.ts +185 -0
  123. package/dist/runtime/dom/actionEffects.js +402 -0
  124. package/dist/runtime/dom/actionEffectsScripts.d.ts +90 -0
  125. package/dist/runtime/dom/actionEffectsScripts.js +426 -0
  126. package/dist/runtime/dom/elementGeometry.d.ts +170 -0
  127. package/dist/runtime/dom/elementGeometry.js +553 -0
  128. package/dist/runtime/dom/elementInfo.d.ts +103 -0
  129. package/dist/runtime/dom/elementInfo.js +256 -0
  130. package/dist/runtime/dom/evalHelpers.d.ts +51 -6
  131. package/dist/runtime/dom/evalHelpers.js +136 -26
  132. package/dist/runtime/dom/eventListeners.d.ts +2 -1
  133. package/dist/runtime/dom/eventListeners.js +184 -47
  134. package/dist/runtime/dom/formDiscovery.d.ts +1 -1
  135. package/dist/runtime/dom/formDiscovery.js +116 -16
  136. package/dist/runtime/dom/formFillHelpers/fill.d.ts +9 -0
  137. package/dist/runtime/dom/formFillHelpers/fill.js +178 -14
  138. package/dist/runtime/dom/formFillHelpers/index.d.ts +2 -2
  139. package/dist/runtime/dom/formFillHelpers/index.js +2 -2
  140. package/dist/runtime/dom/formFillHelpers/pressKey.js +14 -3
  141. package/dist/runtime/dom/formFillHelpers/scroll.d.ts +3 -0
  142. package/dist/runtime/dom/formFillHelpers/scroll.js +60 -18
  143. package/dist/runtime/dom/formFillHelpers/shared.d.ts +17 -0
  144. package/dist/runtime/dom/formFillHelpers/shared.js +25 -1
  145. package/dist/runtime/dom/formFillHelpers/stability.d.ts +20 -6
  146. package/dist/runtime/dom/formFillHelpers/stability.js +50 -19
  147. package/dist/runtime/dom/formSubmitHelpers.d.ts +3 -0
  148. package/dist/runtime/dom/formSubmitHelpers.js +89 -15
  149. package/dist/runtime/dom/frameLayout.d.ts +60 -0
  150. package/dist/runtime/dom/frameLayout.js +140 -0
  151. package/dist/runtime/dom/frameOrigin.d.ts +50 -0
  152. package/dist/runtime/dom/frameOrigin.js +62 -0
  153. package/dist/runtime/dom/frameScopedConnection.d.ts +92 -0
  154. package/dist/runtime/dom/frameScopedConnection.js +252 -0
  155. package/dist/runtime/dom/frameSelection.d.ts +12 -1
  156. package/dist/runtime/dom/frameSelection.js +22 -3
  157. package/dist/runtime/dom/frames.d.ts +61 -5
  158. package/dist/runtime/dom/frames.js +329 -75
  159. package/dist/runtime/dom/inspect.d.ts +28 -0
  160. package/dist/runtime/dom/inspect.js +557 -0
  161. package/dist/runtime/dom/inspectAllStyles.d.ts +62 -0
  162. package/dist/runtime/dom/inspectAllStyles.js +385 -0
  163. package/dist/runtime/dom/inspectCascade.d.ts +94 -0
  164. package/dist/runtime/dom/inspectCascade.js +371 -0
  165. package/dist/runtime/dom/inspectCascadeModel.d.ts +39 -0
  166. package/dist/runtime/dom/inspectCascadeModel.js +232 -0
  167. package/dist/runtime/dom/inspectHints.d.ts +62 -0
  168. package/dist/runtime/dom/inspectHints.js +305 -0
  169. package/dist/runtime/dom/inspectLayoutModel.d.ts +87 -0
  170. package/dist/runtime/dom/inspectLayoutModel.js +346 -0
  171. package/dist/runtime/dom/inspectModel.d.ts +74 -0
  172. package/dist/runtime/dom/inspectModel.js +184 -0
  173. package/dist/runtime/dom/inspectPaintModel.d.ts +157 -0
  174. package/dist/runtime/dom/inspectPaintModel.js +461 -0
  175. package/dist/runtime/dom/inspectRules.d.ts +37 -0
  176. package/dist/runtime/dom/inspectRules.js +101 -0
  177. package/dist/runtime/dom/inspectScripts.d.ts +132 -0
  178. package/dist/runtime/dom/inspectScripts.js +263 -0
  179. package/dist/runtime/dom/inspectTree.d.ts +40 -0
  180. package/dist/runtime/dom/inspectTree.js +134 -0
  181. package/dist/runtime/dom/inspectVariables.d.ts +33 -0
  182. package/dist/runtime/dom/inspectVariables.js +94 -0
  183. package/dist/runtime/dom/inspectWhyModel.d.ts +20 -0
  184. package/dist/runtime/dom/inspectWhyModel.js +134 -0
  185. package/dist/runtime/dom/layout.d.ts +71 -0
  186. package/dist/runtime/dom/layout.js +340 -0
  187. package/dist/runtime/dom/listenerPageScripts.d.ts +72 -0
  188. package/dist/runtime/dom/listenerPageScripts.js +365 -0
  189. package/dist/runtime/dom/listenerSummary.d.ts +136 -11
  190. package/dist/runtime/dom/listenerSummary.js +361 -22
  191. package/dist/runtime/dom/pageActivity.d.ts +41 -0
  192. package/dist/runtime/dom/pageActivity.js +123 -0
  193. package/dist/runtime/dom/reactEventHelpers.d.ts +63 -2
  194. package/dist/runtime/dom/reactEventHelpers.js +220 -41
  195. package/dist/runtime/dom/targetNode.d.ts +80 -27
  196. package/dist/runtime/dom/targetNode.js +249 -33
  197. package/dist/runtime/dom/wait.d.ts +25 -0
  198. package/dist/runtime/dom/wait.js +199 -0
  199. package/dist/runtime/dom/waitCondition.d.ts +71 -0
  200. package/dist/runtime/dom/waitCondition.js +75 -0
  201. package/dist/runtime/page/emulation.d.ts +71 -0
  202. package/dist/runtime/page/emulation.js +117 -0
  203. package/dist/runtime/page/loadingState.d.ts +36 -0
  204. package/dist/runtime/page/loadingState.js +86 -0
  205. package/dist/runtime/page/navigation.d.ts +46 -2
  206. package/dist/runtime/page/navigation.js +69 -33
  207. package/dist/session/QueryCacheManager.d.ts +11 -1
  208. package/dist/session/QueryCacheManager.js +25 -3
  209. package/dist/session/chromeOwners.d.ts +34 -0
  210. package/dist/session/chromeOwners.js +51 -0
  211. package/dist/session/cleanup/staleSession.d.ts +11 -1
  212. package/dist/session/cleanup/staleSession.js +17 -6
  213. package/dist/session/cleanup/userCommands.js +2 -4
  214. package/dist/session/metadata.d.ts +5 -1
  215. package/dist/session/metadata.js +2 -1
  216. package/dist/session/paths.d.ts +77 -3
  217. package/dist/session/paths.js +111 -5
  218. package/dist/session/port.d.ts +31 -7
  219. package/dist/session/port.js +50 -43
  220. package/dist/session/portClaims.d.ts +66 -0
  221. package/dist/session/portClaims.js +284 -0
  222. package/dist/session/sessionList.d.ts +58 -0
  223. package/dist/session/sessionList.js +199 -0
  224. package/dist/session/sessionName.d.ts +46 -0
  225. package/dist/session/sessionName.js +97 -0
  226. package/dist/telemetry/a11y.d.ts +18 -3
  227. package/dist/telemetry/a11y.js +170 -29
  228. package/dist/telemetry/console.d.ts +1 -0
  229. package/dist/telemetry/console.js +100 -5
  230. package/dist/telemetry/network.js +3 -1
  231. package/dist/telemetry/requestKinds.d.ts +32 -0
  232. package/dist/telemetry/requestKinds.js +61 -0
  233. package/dist/telemetry/requestState.d.ts +31 -0
  234. package/dist/telemetry/requestState.js +38 -0
  235. package/dist/types.d.ts +112 -3
  236. package/dist/ui/formatters/a11y.js +3 -0
  237. package/dist/ui/formatters/console/chronological.d.ts +8 -0
  238. package/dist/ui/formatters/console/chronological.js +17 -4
  239. package/dist/ui/formatters/console/json.js +3 -4
  240. package/dist/ui/formatters/console/shared.d.ts +12 -0
  241. package/dist/ui/formatters/console.d.ts +2 -2
  242. package/dist/ui/formatters/console.js +1 -1
  243. package/dist/ui/formatters/details.d.ts +8 -0
  244. package/dist/ui/formatters/details.js +61 -4
  245. package/dist/ui/formatters/dom.d.ts +27 -14
  246. package/dist/ui/formatters/dom.js +88 -59
  247. package/dist/ui/formatters/form.js +29 -18
  248. package/dist/ui/formatters/inspect.d.ts +39 -0
  249. package/dist/ui/formatters/inspect.js +596 -0
  250. package/dist/ui/formatters/keyAttributes.d.ts +19 -0
  251. package/dist/ui/formatters/keyAttributes.js +84 -0
  252. package/dist/ui/formatters/layout.d.ts +31 -0
  253. package/dist/ui/formatters/layout.js +53 -0
  254. package/dist/ui/formatters/listeners.d.ts +3 -2
  255. package/dist/ui/formatters/listeners.js +73 -9
  256. package/dist/ui/formatters/networkHeaders.d.ts +13 -0
  257. package/dist/ui/formatters/networkHeaders.js +36 -3
  258. package/dist/ui/formatters/networkList.d.ts +29 -1
  259. package/dist/ui/formatters/networkList.js +86 -20
  260. package/dist/ui/formatters/preview.js +2 -1
  261. package/dist/ui/formatters/requestStatus.d.ts +1 -17
  262. package/dist/ui/formatters/requestStatus.js +2 -30
  263. package/dist/ui/formatters/sessions.d.ts +12 -0
  264. package/dist/ui/formatters/sessions.js +40 -0
  265. package/dist/ui/formatters/status.d.ts +21 -2
  266. package/dist/ui/formatters/status.js +47 -10
  267. package/dist/ui/formatters/triggeredRequests.d.ts +36 -0
  268. package/dist/ui/formatters/triggeredRequests.js +65 -0
  269. package/dist/ui/formatting.d.ts +19 -0
  270. package/dist/ui/formatting.js +31 -36
  271. package/dist/ui/messages/chrome.d.ts +9 -0
  272. package/dist/ui/messages/chrome.js +17 -5
  273. package/dist/ui/messages/commands.d.ts +504 -14
  274. package/dist/ui/messages/commands.js +835 -21
  275. package/dist/ui/messages/consoleMessages.d.ts +10 -0
  276. package/dist/ui/messages/consoleMessages.js +17 -0
  277. package/dist/ui/messages/hints.js +2 -1
  278. package/dist/ui/messages/networkMessages.d.ts +14 -0
  279. package/dist/ui/messages/networkMessages.js +18 -0
  280. package/dist/ui/messages/preview.js +5 -4
  281. package/dist/ui/messages/session.d.ts +30 -21
  282. package/dist/ui/messages/session.js +48 -26
  283. package/dist/ui/messages/sessionCommand.d.ts +43 -0
  284. package/dist/ui/messages/sessionCommand.js +52 -0
  285. package/dist/utils/async.d.ts +17 -0
  286. package/dist/utils/async.js +36 -0
  287. package/dist/utils/color.d.ts +84 -0
  288. package/dist/utils/color.js +376 -0
  289. package/dist/utils/cssValues.d.ts +109 -0
  290. package/dist/utils/cssValues.js +236 -0
  291. package/dist/utils/http.d.ts +22 -1
  292. package/dist/utils/http.js +28 -9
  293. package/dist/utils/selectorFilters.d.ts +48 -8
  294. package/dist/utils/selectorFilters.js +296 -53
  295. package/dist/utils/shellDetection.d.ts +8 -2
  296. package/dist/utils/shellDetection.js +120 -33
  297. package/dist/utils/suggestions.d.ts +26 -0
  298. package/dist/utils/suggestions.js +73 -0
  299. package/dist/utils/taskMappings.js +10 -0
  300. package/dist/utils/url.d.ts +12 -2
  301. package/dist/utils/url.js +69 -7
  302. package/package.json +1 -1
  303. package/dist/ui/formatters/sessionFormatters.d.ts +0 -58
  304. package/dist/ui/formatters/sessionFormatters.js +0 -121
@@ -0,0 +1,426 @@
1
+ /**
2
+ * Page scripts behind the "what changed" part of DOM action results: one
3
+ * snapshot before the action ({@link EFFECTS_START_SCRIPT}) and one read after
4
+ * it ({@link EFFECTS_READ_SCRIPT}), plus the snapshot a hover takes of what
5
+ * is hidden around its target ({@link REVEAL_SNAPSHOT_JS}).
6
+ */
7
+ import { ELEMENT_DESCRIPTION_JS } from './elementInfo.js';
8
+ /** Class or id words that mark an element as a message (flash, toast, field error) */
9
+ const MESSAGE_WORDS = [
10
+ 'flash',
11
+ 'alert',
12
+ 'error',
13
+ 'toast',
14
+ 'notice',
15
+ 'message',
16
+ 'invalid',
17
+ 'feedback',
18
+ ];
19
+ /** Elements that show messages by role, plus a cheap prefilter for the class and id words */
20
+ const MESSAGE_CANDIDATES = [
21
+ '[role="alert"]',
22
+ '[role="status"]',
23
+ '[aria-live]',
24
+ 'output',
25
+ ...MESSAGE_WORDS.flatMap((word) => [`[class*="${word}" i]`, `[id*="${word}" i]`]),
26
+ ].join(', ');
27
+ /** Class or id words that mark an element as a loading indicator */
28
+ const LOADER_WORDS = ['loading', 'loader', 'spinner'];
29
+ /** Loading indicators by state or role, plus a cheap prefilter for the class and id words */
30
+ const LOADER_CANDIDATES = [
31
+ '[aria-busy="true"]',
32
+ '[role="progressbar"]',
33
+ ...['load', 'spinner'].flatMap((word) => [`[class*="${word}" i]`, `[id*="${word}" i]`]),
34
+ ].join(', ');
35
+ /** Elements anywhere on the page a hover may show (tooltips, menus, popovers) */
36
+ const REVEAL_GLOBAL_CANDIDATES = '[role="tooltip"], [role="menu"], [role="listbox"], [role="dialog"], [popover]';
37
+ /** Elements a hover snapshot looks at, at most */
38
+ const MAX_REVEAL_CANDIDATES = 1500;
39
+ /** Time a hover snapshot may spend before it stops looking (ms) */
40
+ const REVEAL_BUDGET_MS = 8;
41
+ /**
42
+ * Containers that hold a target and the results of its key presses (a form,
43
+ * a search box, a dialog); without one, the target's grandparent is used
44
+ */
45
+ const NEAR_CONTAINERS = 'form, [role="form"], [role="search"], dialog, [role="dialog"], [role="combobox"]';
46
+ /** Added elements reported wherever they are: popups and messages */
47
+ const POPUP_ROLES = /^(tooltip|menu|listbox|dialog|alert|alertdialog|status)$/;
48
+ /** Messages kept per snapshot (after filtering) */
49
+ const MAX_MESSAGES = 50;
50
+ /** Time a message snapshot may spend before it stops looking (ms) */
51
+ const MESSAGES_BUDGET_MS = 5;
52
+ /** Time the list of shown elements may spend before it stops looking (ms) */
53
+ const SHOWN_BUDGET_MS = 10;
54
+ /** Shown elements a read returns at most */
55
+ const MAX_SHOWN = 10;
56
+ /** Added and removed elements a watch keeps */
57
+ const MAX_TRACKED_NODES = 200;
58
+ /** Longer texts are containers (a page, a form), not messages */
59
+ const MAX_MESSAGE_TEXT = 300;
60
+ /** How long a page keeps watching when no read or stop arrives (ms) */
61
+ const MAX_WATCH_MS = 30000;
62
+ /** Bursts of DOM changes a watch keeps (their times) */
63
+ const MAX_BURSTS = 20;
64
+ /**
65
+ * Page-side test whether an element is shown: rendered, not aria-hidden,
66
+ * not `visibility: hidden` and not fully transparent.
67
+ */
68
+ const SHOWN_JS = `(el) => !el.closest('[aria-hidden="true"]') && el.getClientRects().length > 0 &&
69
+ (!el.checkVisibility || el.checkVisibility({ visibilityProperty: true, opacityProperty: true }))`;
70
+ /**
71
+ * Page-side visible text of an element, whitespace collapsed: text in
72
+ * hidden elements, scripts and styles left out, and parts for which `skip`
73
+ * says so. Stops a little over {@link MAX_MESSAGE_TEXT} characters.
74
+ */
75
+ const VISIBLE_TEXT_JS = `(el, skip) => {
76
+ let text = '';
77
+ const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
78
+ while (text.length <= ${MAX_MESSAGE_TEXT} && walker.nextNode()) {
79
+ const parent = walker.currentNode.parentElement;
80
+ if (!parent || /^(script|style|template|noscript)$/.test(parent.localName) || skip(parent)) continue;
81
+ if (parent.checkVisibility && !parent.checkVisibility({ visibilityProperty: true, opacityProperty: true })) continue;
82
+ text += ' ' + walker.currentNode.data;
83
+ }
84
+ return text.replace(/\\s+/g, ' ').trim();
85
+ }`;
86
+ /**
87
+ * Page-side test whether an element is part of a message's chrome rather
88
+ * than its text: aria-hidden parts, buttons, and elements whose class or
89
+ * aria-label names a close/dismiss control (`close`, `btn-close`, `close_x`;
90
+ * not `closeable`, `enclosed` or `disclosure`).
91
+ */
92
+ export const MESSAGE_CHROME_JS = `(node) => {
93
+ const closer = /(^|[-_\\s])(close|dismiss)($|[-_\\s])/i;
94
+ return node.getAttribute('aria-hidden') === 'true' ||
95
+ /^(button|script|style|template)$/.test(node.localName) ||
96
+ node.getAttribute('role') === 'button' ||
97
+ closer.test(node.getAttribute('class') || '') ||
98
+ closer.test(node.getAttribute('aria-label') || '');
99
+ }`;
100
+ /**
101
+ * Page-side list of the messages a page shows: visible elements with an
102
+ * alert/status role, `aria-live`, `<output>`, or a class or id word from
103
+ * {@link MESSAGE_WORDS} (timers, marquees and progress bars left out), with
104
+ * their text (parts matching {@link MESSAGE_CHROME_JS}, such as the "×"
105
+ * close link, left out). Elements are filtered first, then the first
106
+ * {@link MAX_MESSAGES} kept, and the whole pass stops after
107
+ * {@link MESSAGES_BUDGET_MS}. Only the innermost of nested messages is kept,
108
+ * described by tag, id and classes (or its role when it has neither,
109
+ * `h3[role="alert"]`). Each element gets a number from `ids` that stays the
110
+ * same within the document, so a later snapshot can tell a new element from
111
+ * one that was there.
112
+ */
113
+ const MESSAGES_JS = `(ids) => {
114
+ const deadline = performance.now() + ${MESSAGES_BUDGET_MS};
115
+ const description = ${ELEMENT_DESCRIPTION_JS};
116
+ const chrome = ${MESSAGE_CHROME_JS};
117
+ const shown = ${SHOWN_JS};
118
+ const visibleText = ${VISIBLE_TEXT_JS};
119
+ const describe = (el) => {
120
+ const text = description(el);
121
+ const role = el.getAttribute('role');
122
+ return text === el.localName && role ? text + '[role="' + role + '"]' : text;
123
+ };
124
+ const word = /\\b(${MESSAGE_WORDS.join('|')})\\b/i;
125
+ const named = (el) => !/^(timer|marquee|progressbar)$/.test(el.getAttribute('role') || '') &&
126
+ (el.matches('[role="alert"], [role="status"], [aria-live]:not([aria-live="off"]), output') ||
127
+ word.test(el.getAttribute('class') || '') || word.test(el.id || ''));
128
+ const inChrome = (node, el) => {
129
+ for (let n = node; n && n !== el; n = n.parentElement) if (chrome(n)) return true;
130
+ return false;
131
+ };
132
+ const found = [];
133
+ for (const el of document.querySelectorAll(${JSON.stringify(MESSAGE_CANDIDATES)})) {
134
+ if (found.length >= ${MAX_MESSAGES} || performance.now() > deadline) break;
135
+ if (!named(el) || !shown(el)) continue;
136
+ const text = visibleText(el, (node) => inChrome(node, el));
137
+ if (text !== '' && text.length <= ${MAX_MESSAGE_TEXT}) found.push({ el: el, text: text });
138
+ }
139
+ return found
140
+ .filter((m) => !found.some((other) => other !== m && m.el.contains(other.el)))
141
+ .map((m) => {
142
+ let id = ids.map.get(m.el);
143
+ if (id === undefined) {
144
+ id = ids.next++;
145
+ ids.map.set(m.el, id);
146
+ }
147
+ return { id: id, text: m.text, element: describe(m.el) };
148
+ });
149
+ }`;
150
+ /**
151
+ * Page-side list of the loading indicators shown: elements with
152
+ * `aria-busy="true"`, a progressbar role, or a class or id word from
153
+ * {@link LOADER_WORDS} (`is-loading`, `spinner`; not `lazyloading`).
154
+ */
155
+ const LOADERS_JS = `() => {
156
+ const shown = ${SHOWN_JS};
157
+ const word = /\\b(${LOADER_WORDS.join('|')})\\b/i;
158
+ const loader = (el) => el.getAttribute('aria-busy') === 'true' || el.getAttribute('role') === 'progressbar' ||
159
+ word.test(el.getAttribute('class') || '') || word.test(el.id || '');
160
+ return Array.from(document.querySelectorAll(${JSON.stringify(LOADER_CANDIDATES)})).filter((el) => loader(el) && shown(el));
161
+ }`;
162
+ /**
163
+ * Page-side snapshot a hover takes right before the mouse moves (called by
164
+ * the click script with the hovered element): the elements around it (its
165
+ * parent and everything in it) and the tooltips, menus, listboxes, dialogs
166
+ * and popovers anywhere on the page that are hidden, at most
167
+ * {@link MAX_REVEAL_CANDIDATES} looked at within {@link REVEAL_BUDGET_MS}.
168
+ * They are kept by identity in the action's watch, so its read can tell
169
+ * which of them the hover revealed, also through CSS `:hover` rules that
170
+ * change no DOM, and elements moving in the page can't pass for revealed
171
+ * ones. Does nothing without a running watch (another frame).
172
+ */
173
+ export const REVEAL_SNAPSHOT_JS = `(el) => {
174
+ const state = window.__bdgEffects;
175
+ if (!state || state.stopped) return;
176
+ const deadline = performance.now() + ${REVEAL_BUDGET_MS};
177
+ const shown = ${SHOWN_JS};
178
+ const parent = el.parentElement;
179
+ const scope = parent && !/^(body|html)$/.test(parent.localName) ? parent : el;
180
+ const hidden = [];
181
+ let looked = 0;
182
+ const room = () => looked < ${MAX_REVEAL_CANDIDATES} && performance.now() <= deadline;
183
+ const look = (candidate) => {
184
+ looked++;
185
+ if (!shown(candidate)) hidden.push(candidate);
186
+ };
187
+ for (const candidate of document.querySelectorAll(${JSON.stringify(REVEAL_GLOBAL_CANDIDATES)})) {
188
+ if (!room()) break;
189
+ look(candidate);
190
+ }
191
+ const walker = document.createTreeWalker(scope, NodeFilter.SHOW_ELEMENT);
192
+ for (let node = scope; node && room(); node = walker.nextNode()) look(node);
193
+ state.reveal = { target: el, hidden: hidden };
194
+ }`;
195
+ /**
196
+ * Page-side container whose added elements count as an action's result:
197
+ * the target's form, search box, dialog or combobox, else its grandparent
198
+ * (its parent when the grandparent is the body).
199
+ */
200
+ const NEAR_SCOPE_JS = `(target) => {
201
+ const container = target.closest(${JSON.stringify(NEAR_CONTAINERS)});
202
+ if (container) return container;
203
+ const parent = target.parentElement || target;
204
+ const grandparent = parent.parentElement;
205
+ return grandparent && !/^(body|html)$/.test(grandparent.localName) ? grandparent : parent;
206
+ }`;
207
+ /**
208
+ * Page-side list of the elements an action showed: elements added during
209
+ * the watch inside the target's container ({@link NEAR_SCOPE_JS}) or, anywhere,
210
+ * popups and messages (tooltip, menu, listbox, dialog, alert and status
211
+ * roles, `aria-live`, message-like classes), plus, after a hover, the
212
+ * elements hidden before it that are shown now ({@link REVEAL_SNAPSHOT_JS}).
213
+ * Background widgets elsewhere on the page do not count. Only shown ones
214
+ * with visible text count, the outermost of nested ones, and not those
215
+ * whose text a removed element had (a re-render). At most
216
+ * {@link MAX_SHOWN}, within {@link SHOWN_BUDGET_MS}.
217
+ */
218
+ export const SHOWN_ELEMENTS_JS = `(state) => {
219
+ const deadline = performance.now() + ${SHOWN_BUDGET_MS};
220
+ const describe = ${ELEMENT_DESCRIPTION_JS};
221
+ const shown = ${SHOWN_JS};
222
+ const visibleText = ${VISIBLE_TEXT_JS};
223
+ const word = /\\b(${MESSAGE_WORDS.join('|')})\\b/i;
224
+ const target = state.reveal ? state.reveal.target : state.keyTarget;
225
+ const scope = target && target.isConnected ? (${NEAR_SCOPE_JS})(target) : null;
226
+ const popup = (el) => ${POPUP_ROLES}.test(el.getAttribute('role') || '') || el.hasAttribute('popover') ||
227
+ (el.hasAttribute('aria-live') && el.getAttribute('aria-live') !== 'off') ||
228
+ word.test(el.getAttribute('class') || '') || word.test(el.id || '');
229
+ const near = (el) => (scope !== null && scope.contains(el)) || popup(el);
230
+ const contentOf = (node) => (node.textContent || '').replace(/\\s+/g, ' ').trim();
231
+ const removed = new Set(state.removed.map(contentOf));
232
+ const candidates = new Set(state.added.filter((node) => node.isConnected && near(node)));
233
+ if (state.reveal) for (const el of state.reveal.hidden) if (el.isConnected) candidates.add(el);
234
+ const found = [];
235
+ for (const el of candidates) {
236
+ if (performance.now() > deadline) break;
237
+ if (!shown(el) || removed.has(contentOf(el))) continue;
238
+ const text = visibleText(el, () => false);
239
+ if (text !== '') found.push({ el: el, text: text });
240
+ }
241
+ return found
242
+ .filter((m) => !found.some((other) => other !== m && other.el.contains(m.el)))
243
+ .slice(0, ${MAX_SHOWN})
244
+ .map((m) => ({ text: m.text, element: describe(m.el) }));
245
+ }`;
246
+ /**
247
+ * Page-side test whether a mutation is only focus/hover churn: a class
248
+ * change on an element the action's events hit (`targets`) that only adds
249
+ * or removes classes containing "focus" or "hover".
250
+ */
251
+ export const CHURN_ONLY_JS = `(record, targets) => {
252
+ if (record.type !== 'attributes' || record.attributeName !== 'class' || !targets.has(record.target)) return false;
253
+ const tokens = (text) => new Set((text || '').split(/\\s+/).filter(Boolean));
254
+ const before = tokens(record.oldValue);
255
+ const after = tokens(record.target.getAttribute('class'));
256
+ const changed = [...before].filter((c) => !after.has(c)).concat([...after].filter((c) => !before.has(c)));
257
+ return changed.every((c) => /focus|hover/i.test(c));
258
+ }`;
259
+ /**
260
+ * Page-side test whether a mutation changes the page's structure or state
261
+ * rather than only animating it: elements added or removed, or an attribute
262
+ * other than `style` changed. Text-only changes (clocks, counters) and style
263
+ * changes (script-driven animations) do not count.
264
+ */
265
+ export const STRUCTURAL_CHANGE_JS = `(record) => {
266
+ if (record.type === 'attributes') return record.attributeName !== 'style';
267
+ if (record.type !== 'childList') return false;
268
+ const element = (node) => node.nodeType === 1;
269
+ return Array.from(record.addedNodes).some(element) || Array.from(record.removedNodes).some(element);
270
+ }`;
271
+ /**
272
+ * Page-side reason why "no effect" can't be claimed even without DOM
273
+ * changes, or undefined: `clipboard` (a copy or cut happened), `no-event`
274
+ * (no event reached the page), `control` (form controls, labels, media,
275
+ * frames, popover/command buttons: their effect needs no DOM change),
276
+ * `new-window` (download or `target` links), `external-link` (mailto:, tel:,
277
+ * javascript: and other non-http links), `closed-shadow` (a custom element
278
+ * whose inside is not observed) or `focus` (focus moved to an element that
279
+ * may reveal content with CSS).
280
+ */
281
+ export const UNCERTAIN_JS = `(state, active) => {
282
+ if (state.copied) return 'clipboard';
283
+ if (state.targets.size === 0) return 'no-event';
284
+ const controls = /^(input|select|textarea|option|label|canvas|video|audio|iframe|embed|object)$/;
285
+ for (const node of state.path) {
286
+ if (controls.test(node.localName) || node.isContentEditable) return 'control';
287
+ if (node.hasAttribute('popovertarget') || node.hasAttribute('commandfor')) return 'control';
288
+ if (node.localName === 'a' && node.hasAttribute('href')) {
289
+ if (node.hasAttribute('download') || (node.target && node.target !== '_self')) return 'new-window';
290
+ if (!/^https?:$/.test(node.protocol)) return 'external-link';
291
+ }
292
+ }
293
+ for (const node of state.targets) if (node.localName.includes('-') && !node.shadowRoot) return 'closed-shadow';
294
+ const plain = (node) => /^(body|button|summary)$/.test(node.localName) ||
295
+ (node.localName === 'a' && node.hasAttribute('href')) ||
296
+ (node.localName === 'input' && /^(button|submit|reset)$/i.test(node.type || ''));
297
+ if (active && active !== state.focus && !plain(active)) return 'focus';
298
+ return undefined;
299
+ }`;
300
+ /**
301
+ * Page-side signs, at a read, that the page is still working on the
302
+ * action's result: how long ago each recent burst of DOM changes was (ms,
303
+ * newest last), and a loading indicator shown since the start (described).
304
+ */
305
+ const SETTLE_JS = `(state) => {
306
+ const now = performance.now();
307
+ const describe = ${ELEMENT_DESCRIPTION_JS};
308
+ const loader = (${LOADERS_JS})().find((el) => !state.loaders.has(el));
309
+ return {
310
+ burstAges: state.bursts.map((time) => Math.round(now - time)),
311
+ loading: loader ? describe(loader) : null
312
+ };
313
+ }`;
314
+ /**
315
+ * Snapshot before an action, left in `window.__bdgEffects`: the messages
316
+ * and loading indicators shown, and a MutationObserver (on the document,
317
+ * its open shadow roots and any shadow root attached while watching, which
318
+ * also counts as a change) counting changes other than
319
+ * {@link CHURN_ONLY_JS}, keeping the elements added and removed and the
320
+ * times of {@link STRUCTURAL_CHANGE_JS} bursts. Capture listeners record
321
+ * which elements the action's events reached, the first key press's target,
322
+ * copy/cut events and the scroll position at the first press (a click
323
+ * scrolls its target into view first). The watch stops itself after
324
+ * {@link MAX_WATCH_MS}, so a snapshot that ran late (after a navigation,
325
+ * with nobody reading it) leaves nothing behind. Evaluates to the URL and
326
+ * the messages.
327
+ */
328
+ export const EFFECTS_START_SCRIPT = `(() => {
329
+ if (window.__bdgEffects) window.__bdgEffects.stop();
330
+ const churnOnly = ${CHURN_ONLY_JS};
331
+ const structural = ${STRUCTURAL_CHANGE_JS};
332
+ const ids = { map: new WeakMap(), next: 1 };
333
+ const state = {
334
+ ids: ids, changes: 0, targets: new Set(), path: new Set(), focus: document.activeElement,
335
+ pressScroll: null, copied: false, stopped: false, added: [], removed: [], bursts: [],
336
+ keyTarget: null, loaders: new Set((${LOADERS_JS})())
337
+ };
338
+ const keep = (list, nodes) => {
339
+ for (const node of nodes) if (node.nodeType === 1 && list.length < ${MAX_TRACKED_NODES}) list.push(node);
340
+ };
341
+ const count = (records) => {
342
+ let burst = false;
343
+ for (const record of records) {
344
+ if (churnOnly(record, state.targets)) continue;
345
+ state.changes++;
346
+ burst = burst || structural(record);
347
+ if (record.type === 'childList') {
348
+ keep(state.added, record.addedNodes);
349
+ keep(state.removed, record.removedNodes);
350
+ }
351
+ }
352
+ if (!burst) return;
353
+ state.bursts.push(performance.now());
354
+ if (state.bursts.length > ${MAX_BURSTS}) state.bursts.shift();
355
+ };
356
+ const observer = new MutationObserver(count);
357
+ const options = { subtree: true, childList: true, characterData: true, attributes: true, attributeOldValue: true };
358
+ const observe = (root) => {
359
+ observer.observe(root, options);
360
+ for (const el of root.querySelectorAll('*')) if (el.shadowRoot) observe(el.shadowRoot);
361
+ };
362
+ observe(document);
363
+ const attachShadow = Element.prototype.attachShadow;
364
+ const watchedAttach = function (init) {
365
+ const root = attachShadow.call(this, init);
366
+ state.changes++;
367
+ observer.observe(root, options);
368
+ return root;
369
+ };
370
+ Element.prototype.attachShadow = watchedAttach;
371
+ const types = ['pointerdown', 'mousedown', 'click', 'keydown', 'focusin', 'submit', 'mouseover', 'input', 'change', 'copy', 'cut'];
372
+ const pressTypes = ['pointerdown', 'mousedown', 'click', 'keydown', 'submit'];
373
+ const record = (event) => {
374
+ if (event.type === 'copy' || event.type === 'cut') state.copied = true;
375
+ const path = event.composedPath().filter((node) => node.nodeType === 1);
376
+ if (path[0]) state.targets.add(path[0]);
377
+ if (path[0] && !state.keyTarget && event.type === 'keydown') state.keyTarget = path[0];
378
+ path.forEach((node) => state.path.add(node));
379
+ if (!state.pressScroll && pressTypes.includes(event.type)) state.pressScroll = [scrollX, scrollY];
380
+ };
381
+ types.forEach((type) => window.addEventListener(type, record, true));
382
+ state.flush = () => count(observer.takeRecords());
383
+ state.stop = () => {
384
+ if (state.stopped) return;
385
+ state.stopped = true;
386
+ clearTimeout(expiry);
387
+ observer.disconnect();
388
+ if (Element.prototype.attachShadow === watchedAttach) Element.prototype.attachShadow = attachShadow;
389
+ types.forEach((type) => window.removeEventListener(type, record, true));
390
+ };
391
+ const expiry = setTimeout(state.stop, ${MAX_WATCH_MS});
392
+ window.__bdgEffects = state;
393
+ return { href: location.href, messages: (${MESSAGES_JS})(ids) };
394
+ })()`;
395
+ /**
396
+ * Read after an action, called with `(stop, shown)`: `stop` also stops
397
+ * watching, `shown` lists the elements the action showed
398
+ * ({@link SHOWN_ELEMENTS_JS}). Returns the URL, the messages shown and,
399
+ * when the snapshot is still there (same document), the number of changes
400
+ * counted (plus one when the page scrolled after the press), why "no
401
+ * effect" could not be claimed ({@link UNCERTAIN_JS}) and whether the page
402
+ * is still working ({@link SETTLE_JS}). `fresh` means a new document
403
+ * (everything shown is new).
404
+ */
405
+ export const EFFECTS_READ_SCRIPT = `((stop, shown) => {
406
+ const state = window.__bdgEffects;
407
+ if (!state) return { href: location.href, fresh: true, messages: (${MESSAGES_JS})({ map: new WeakMap(), next: 1 }) };
408
+ if (!state.stopped) state.flush();
409
+ if (stop) {
410
+ state.stop();
411
+ delete window.__bdgEffects;
412
+ }
413
+ const scrolled = state.pressScroll !== null && (state.pressScroll[0] !== scrollX || state.pressScroll[1] !== scrollY);
414
+ return {
415
+ href: location.href,
416
+ fresh: false,
417
+ changes: state.changes + (scrolled ? 1 : 0),
418
+ uncertain: (${UNCERTAIN_JS})(state, document.activeElement),
419
+ messages: (${MESSAGES_JS})(state.ids),
420
+ settle: (${SETTLE_JS})(state),
421
+ shown: shown ? (${SHOWN_ELEMENTS_JS})(state) : undefined
422
+ };
423
+ })`;
424
+ /** Stops the watch {@link EFFECTS_START_SCRIPT} left (when no read stopped it) */
425
+ export const EFFECTS_STOP_SCRIPT = 'if (window.__bdgEffects) { window.__bdgEffects.stop(); delete window.__bdgEffects; }';
426
+ //# sourceMappingURL=actionEffectsScripts.js.map
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Where elements are relative to the viewport of the top-level page.
3
+ *
4
+ * The page-side scripts measure an element in top-level viewport coordinates
5
+ * (adding the offsets of the same-origin iframes it is in) together with what
6
+ * clips it: the viewports of those iframes and ancestors that cut off
7
+ * overflowing content (scroll containers, `overflow: hidden`). Classifying the
8
+ * measurements is done here, outside the page, so `dom query` and `dom layout`
9
+ * agree and the rules can be tested without a browser.
10
+ */
11
+ import type { LayoutBox, LayoutPoint, LayoutSize } from '../../ipc/protocol/domTypes.js';
12
+ import type { ViewportPosition } from '../../types.js';
13
+ /** Measurements of one element ({@link ELEMENT_GEOMETRY_JS}). */
14
+ export interface ElementGeometry {
15
+ /** Border box in top-level viewport coordinates */
16
+ rect: LayoutBox;
17
+ /** Area its iframes and overflow-clipping ancestors leave visible, in the same coordinates */
18
+ clip: LayoutBox | null;
19
+ /** Whether overlay scrollbars of the clipping containers show along the clip's right and bottom edges */
20
+ clipOverlay: OverlayEdges;
21
+ /** Innermost ancestor or iframe cutting off part of it, e.g. `ul#list` */
22
+ clipper: string | null;
23
+ /** Why it cannot be seen regardless of position, e.g. `display: none`, `clipped by div#acc: zero height` */
24
+ hidden: string | null;
25
+ /**
26
+ * Why it cannot be seen although it is rendered ({@link INVISIBLE_REASON_JS}),
27
+ * e.g. `opacity: 0 on div#menu`
28
+ */
29
+ invisible: string | null;
30
+ /** Inside an `inert` element: shown, but not interactive */
31
+ inert: boolean;
32
+ /** Fixed to the top-level viewport (it or a container is `position: fixed`): page scroll does not move it */
33
+ fixed: boolean;
34
+ /** It or an ancestor is `position: sticky`: page scroll moves it only until it sticks */
35
+ sticky?: boolean;
36
+ /** How far the top-level page can scroll from where it is now */
37
+ pageScroll: ScrollRange;
38
+ /**
39
+ * Why the top-level page cannot scroll although content is below the fold
40
+ * ({@link SCROLL_LOCK_JS}); null when it is not locked
41
+ */
42
+ scrollLock?: ScrollLock | null;
43
+ /** Offset of its document's viewport within the top-level viewport (iframes) */
44
+ offset: LayoutPoint;
45
+ }
46
+ /** What keeps the top-level page from scrolling ({@link SCROLL_LOCK_JS}). */
47
+ export interface ScrollLock {
48
+ /** The styles locking it, e.g. `position: fixed, overflow: hidden on body` */
49
+ by: string;
50
+ /** A visible dialog that is likely the reason, e.g. `div#consent`; null when there is none */
51
+ dialog: string | null;
52
+ }
53
+ /** Edges of a viewport or clip along which overlay scrollbars (that take no space) show after a scroll. */
54
+ export interface OverlayEdges {
55
+ right: boolean;
56
+ bottom: boolean;
57
+ }
58
+ /** Distances (CSS px, never negative) a page can scroll in each direction. */
59
+ export interface ScrollRange {
60
+ left: number;
61
+ up: number;
62
+ right: number;
63
+ down: number;
64
+ }
65
+ /** How an element relates to the viewport ({@link classifyViewportPosition}). */
66
+ export interface ViewportPlacement {
67
+ inViewport: ViewportPosition;
68
+ /** Share in view (1-99), for `partly` */
69
+ percentVisible?: number;
70
+ /** Why it is `hidden` */
71
+ hiddenReason?: string;
72
+ /**
73
+ * Page scroll that brings it fully into view, when the page can scroll there:
74
+ * the smallest one for an element partly in view, centring it for one out of view
75
+ */
76
+ scrollBy?: LayoutPoint;
77
+ /** Ancestor or iframe cutting it off (page scroll alone does not show it) */
78
+ clippedBy?: string;
79
+ /** Why page scroll cannot bring it fully into view ({@link OFF_SCREEN_REASONS}) */
80
+ offScreenReason?: string;
81
+ }
82
+ /** Why page scroll cannot bring an element that is not fully in view into view. */
83
+ export declare const OFF_SCREEN_REASONS: {
84
+ readonly fixed: "fixed position, page scroll does not move it";
85
+ readonly sticky: "sticky position, page scroll moves it only until it sticks";
86
+ readonly outOfRange: "beyond the page's scroll range";
87
+ };
88
+ /**
89
+ * Page-side size of a window's viewport without scrollbars (the window size
90
+ * for quirks-mode documents, whose root element is as large as the content).
91
+ */
92
+ export declare const VIEWPORT_SIZE_JS = "(view) => {\n const root = view.document.documentElement;\n const standards = view.document.compatMode === 'CSS1Compat' && root;\n return {\n width: standards ? root.clientWidth : view.innerWidth,\n height: standards ? root.clientHeight : view.innerHeight\n };\n}";
93
+ /**
94
+ * Page-side distances a window's page can scroll in each direction from its
95
+ * current position. Right-to-left pages scroll to negative `scrollX`. Content
96
+ * that a scrolling body cuts off is reported through the body as a clipper.
97
+ */
98
+ export declare const SCROLL_RANGE_JS = "(view) => {\n const doc = view.document;\n const scroller = doc.scrollingElement || doc.documentElement;\n const maxX = Math.max(0, scroller.scrollWidth - scroller.clientWidth);\n const maxY = Math.max(0, scroller.scrollHeight - scroller.clientHeight);\n const rtl = view.scrollX < 0 || view.getComputedStyle(doc.documentElement).direction === 'rtl';\n const left = rtl ? maxX + view.scrollX : view.scrollX;\n return { left: Math.max(0, left), up: Math.max(0, view.scrollY), right: Math.max(0, maxX - left), down: Math.max(0, maxY - view.scrollY) };\n}";
99
+ /**
100
+ * Page-side offset of an iframe's content (inside its border and padding)
101
+ * within the viewport of the document holding the iframe.
102
+ */
103
+ export declare const FRAME_OFFSET_JS = "(frame) => {\n const rect = frame.getBoundingClientRect();\n const style = frame.ownerDocument.defaultView.getComputedStyle(frame);\n return {\n x: rect.left + frame.clientLeft + parseFloat(style.paddingLeft),\n y: rect.top + frame.clientTop + parseFloat(style.paddingTop)\n };\n}";
104
+ /**
105
+ * Page-side test of computed styles: true when they only scale or move the
106
+ * box (no `rotate`, and a 2D `transform` matrix without rotation or skew), so
107
+ * its bounding box is the box itself, scaled.
108
+ */
109
+ export declare const SCALES_ONLY_JS = "(style) => {\n if (style.rotate && style.rotate !== 'none') return false;\n if (!style.transform || style.transform === 'none') return true;\n const matrix = /^matrix\\(([^)]*)\\)$/.exec(style.transform);\n if (!matrix) return false;\n const values = matrix[1].split(',').map(parseFloat);\n return Math.abs(values[1]) < 1e-6 && Math.abs(values[2]) < 1e-6;\n}";
110
+ /** Page-side test of a `clip-path` that cuts everything away: `inset()` with percentages leaving no area. */
111
+ export declare const CLIP_PATH_CUTS_ALL_JS = "(clipPath) => {\n const inset = /^inset\\(([^)]*)\\)/.exec(clipPath || '');\n const values = inset ? inset[1].split(' round ')[0].trim().split(/\\s+/) : [];\n if (values.length === 0 || values.some((v) => !/%$/.test(v))) return false;\n const [top, right = top, bottom = top, left = right] = values.map(parseFloat);\n return top + bottom >= 100 || left + right >= 100;\n}";
112
+ /**
113
+ * Page-side test of a `clip` that cuts everything away: `rect()` with no area
114
+ * on an absolutely positioned or fixed element (the "visually hidden"
115
+ * pattern; `clip` applies to no other element).
116
+ */
117
+ export declare const CLIP_RECT_CUTS_ALL_JS = "(position, clip) => {\n if ((position !== 'absolute' && position !== 'fixed') || !/^rect\\(/.test(clip || '')) return false;\n const edges = (clip.match(/-?[\\d.]+/g) || []).map(Number);\n return edges.length === 4 && (edges[1] <= edges[3] || edges[2] <= edges[0]);\n}";
118
+ /**
119
+ * Page-side measurement of an element ({@link ElementGeometry}): its box in
120
+ * top-level viewport coordinates, its clip by ancestors
121
+ * ({@link ANCESTOR_CLIP_JS}) and by the viewports of its iframes, why it
122
+ * cannot be seen at all (not rendered, or inside a clipping container
123
+ * collapsed to zero size), why a rendered one is still invisible
124
+ * ({@link INVISIBLE_REASON_JS}), whether it is inert (an `inert` element
125
+ * around it, through shadow roots) or fixed to the top-level viewport, and how
126
+ * far the top-level page can scroll ({@link SCROLL_RANGE_JS}) or what locks
127
+ * its scrolling ({@link SCROLL_LOCK_JS}). Content of a body fixed to lock the
128
+ * page is not counted as fixed: it is in-flow content the lock holds in place.
129
+ *
130
+ * Rendering is decided by `checkVisibility()`, so content Chrome skips
131
+ * (inside a closed `<details>`, under `content-visibility: hidden`) is hidden
132
+ * although it still has a box. Content skipped by `content-visibility: auto`
133
+ * is not: it is rendered once scrolled near the viewport.
134
+ */
135
+ export declare const ELEMENT_GEOMETRY_JS: string;
136
+ /**
137
+ * How a scroll brings an element into view: `centre` it (an element out of
138
+ * view, like `bdg dom scroll <selector>`, so sticky headers and fixed footers
139
+ * at the edges do not cover it), or the `minimal` scroll that shows all of
140
+ * it (an element partly in view: the part cut off at one edge).
141
+ */
142
+ export type ScrollAim = 'centre' | 'minimal';
143
+ /**
144
+ * Where along one axis a scroll should bring a span's start (in the current
145
+ * viewport coordinates): centred, or just inside the edge cutting it off; a
146
+ * span larger than the viewport gets its start aligned either way.
147
+ *
148
+ * @param start - Start of the span in viewport coordinates
149
+ * @param size - Length of the span
150
+ * @param viewSize - Length of the viewport
151
+ * @param aim - Centre it, or the smallest scroll showing all of it
152
+ * @returns Scroll that would do it (negative: back), before limiting it to the page
153
+ */
154
+ export declare function scrollTarget(start: number, size: number, viewSize: number, aim: ScrollAim): number;
155
+ /**
156
+ * Classify where an element is relative to the top-level viewport.
157
+ *
158
+ * Visible parts are what lies inside the viewport and the element's clip
159
+ * (iframes, overflow containers). An element with no visible part is `above`,
160
+ * `below`, `left` or `right` of the viewport (or of its clip, e.g. scrolled
161
+ * out of a list), and `hidden` when it is not rendered at all. Being inert
162
+ * does not change the position: inert elements are shown.
163
+ *
164
+ * @param geometry - Page-side measurements
165
+ * @param viewport - Top-level viewport size
166
+ * @returns Position, with the visible share, hidden reason, clipping
167
+ * ancestor or page scroll when relevant
168
+ */
169
+ export declare function classifyViewportPosition(geometry: ElementGeometry, viewport: LayoutSize): ViewportPlacement;
170
+ //# sourceMappingURL=elementGeometry.d.ts.map