foldkit-primitives 0.15.3 → 0.16.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 (422) hide show
  1. package/dist/device/fullscreen.d.ts +28 -0
  2. package/dist/device/fullscreen.d.ts.map +1 -0
  3. package/dist/device/fullscreen.js +69 -0
  4. package/dist/device/fullscreen.js.map +1 -0
  5. package/dist/device/geolocation.d.ts +56 -0
  6. package/dist/device/geolocation.d.ts.map +1 -0
  7. package/dist/device/geolocation.js +87 -0
  8. package/dist/device/geolocation.js.map +1 -0
  9. package/dist/device/index.d.ts +5 -0
  10. package/dist/device/index.js +6 -0
  11. package/dist/device/media-devices.d.ts +88 -0
  12. package/dist/device/media-devices.d.ts.map +1 -0
  13. package/dist/device/media-devices.js +117 -0
  14. package/dist/device/media-devices.js.map +1 -0
  15. package/dist/device/media-stream.d.ts +93 -0
  16. package/dist/device/media-stream.d.ts.map +1 -0
  17. package/dist/device/media-stream.js +106 -0
  18. package/dist/device/media-stream.js.map +1 -0
  19. package/dist/device/permissions.d.ts +106 -0
  20. package/dist/device/permissions.d.ts.map +1 -0
  21. package/dist/device/permissions.js +143 -0
  22. package/dist/device/permissions.js.map +1 -0
  23. package/dist/dom/autofocus.d.ts +15 -0
  24. package/dist/dom/autofocus.d.ts.map +1 -0
  25. package/dist/dom/autofocus.js +22 -0
  26. package/dist/dom/autofocus.js.map +1 -0
  27. package/dist/dom/clipboard.d.ts +30 -0
  28. package/dist/dom/clipboard.d.ts.map +1 -0
  29. package/dist/dom/clipboard.js +50 -0
  30. package/dist/dom/clipboard.js.map +1 -0
  31. package/dist/dom/editable-text.d.ts +72 -0
  32. package/dist/dom/editable-text.d.ts.map +1 -0
  33. package/dist/dom/editable-text.js +232 -0
  34. package/dist/dom/editable-text.js.map +1 -0
  35. package/dist/dom/fluid-hover.d.ts +93 -0
  36. package/dist/dom/fluid-hover.d.ts.map +1 -0
  37. package/dist/dom/fluid-hover.js +294 -0
  38. package/dist/dom/fluid-hover.js.map +1 -0
  39. package/dist/dom/focus-scope.d.ts +21 -0
  40. package/dist/dom/focus-scope.d.ts.map +1 -0
  41. package/dist/dom/focus-scope.js +93 -0
  42. package/dist/dom/focus-scope.js.map +1 -0
  43. package/dist/dom/follow-tab-stop.d.ts +11 -0
  44. package/dist/dom/follow-tab-stop.d.ts.map +1 -0
  45. package/dist/dom/follow-tab-stop.js +54 -0
  46. package/dist/dom/follow-tab-stop.js.map +1 -0
  47. package/dist/dom/image-decode.d.ts +27 -0
  48. package/dist/dom/image-decode.d.ts.map +1 -0
  49. package/dist/dom/image-decode.js +50 -0
  50. package/dist/dom/image-decode.js.map +1 -0
  51. package/dist/dom/index.d.ts +24 -0
  52. package/dist/dom/index.js +25 -0
  53. package/dist/dom/input-mask.d.ts +35 -0
  54. package/dist/dom/input-mask.d.ts.map +1 -0
  55. package/dist/dom/input-mask.js +90 -0
  56. package/dist/dom/input-mask.js.map +1 -0
  57. package/dist/dom/keep-in-view.d.ts +16 -0
  58. package/dist/dom/keep-in-view.d.ts.map +1 -0
  59. package/dist/dom/keep-in-view.js +38 -0
  60. package/dist/dom/keep-in-view.js.map +1 -0
  61. package/dist/dom/keyboard-inset.d.ts +29 -0
  62. package/dist/dom/keyboard-inset.d.ts.map +1 -0
  63. package/dist/dom/keyboard-inset.js +45 -0
  64. package/dist/dom/keyboard-inset.js.map +1 -0
  65. package/dist/dom/layers.d.ts +6 -0
  66. package/dist/dom/layers.d.ts.map +1 -0
  67. package/dist/dom/layers.js +35 -0
  68. package/dist/dom/layers.js.map +1 -0
  69. package/dist/dom/measure.d.ts +42 -0
  70. package/dist/dom/measure.d.ts.map +1 -0
  71. package/dist/dom/measure.js +123 -0
  72. package/dist/dom/measure.js.map +1 -0
  73. package/dist/dom/move.d.ts +45 -0
  74. package/dist/dom/move.d.ts.map +1 -0
  75. package/dist/dom/move.js +96 -0
  76. package/dist/dom/move.js.map +1 -0
  77. package/dist/dom/pointed-links.d.ts +13 -0
  78. package/dist/dom/pointed-links.d.ts.map +1 -0
  79. package/dist/dom/pointed-links.js +59 -0
  80. package/dist/dom/pointed-links.js.map +1 -0
  81. package/dist/dom/pointer-drag.d.ts +132 -0
  82. package/dist/dom/pointer-drag.d.ts.map +1 -0
  83. package/dist/dom/pointer-drag.js +307 -0
  84. package/dist/dom/pointer-drag.js.map +1 -0
  85. package/dist/dom/pointer-position.d.ts +133 -0
  86. package/dist/dom/pointer-position.d.ts.map +1 -0
  87. package/dist/dom/pointer-position.js +173 -0
  88. package/dist/dom/pointer-position.js.map +1 -0
  89. package/dist/dom/script-loader.d.ts +12 -0
  90. package/dist/dom/script-loader.d.ts.map +1 -0
  91. package/dist/dom/script-loader.js +54 -0
  92. package/dist/dom/script-loader.js.map +1 -0
  93. package/dist/dom/scroll-bars.d.ts +52 -0
  94. package/dist/dom/scroll-bars.d.ts.map +1 -0
  95. package/dist/dom/scroll-bars.js +259 -0
  96. package/dist/dom/scroll-bars.js.map +1 -0
  97. package/dist/dom/scroll-settle.d.ts +33 -0
  98. package/dist/dom/scroll-settle.d.ts.map +1 -0
  99. package/dist/dom/scroll-settle.js +84 -0
  100. package/dist/dom/scroll-settle.js.map +1 -0
  101. package/dist/dom/scroll.d.ts +21 -0
  102. package/dist/dom/scroll.d.ts.map +1 -0
  103. package/dist/dom/scroll.js +141 -0
  104. package/dist/dom/scroll.js.map +1 -0
  105. package/dist/dom/share.d.ts +19 -0
  106. package/dist/dom/share.d.ts.map +1 -0
  107. package/dist/dom/share.js +41 -0
  108. package/dist/dom/share.js.map +1 -0
  109. package/dist/dom/swipe.d.ts +121 -0
  110. package/dist/dom/swipe.d.ts.map +1 -0
  111. package/dist/dom/swipe.js +291 -0
  112. package/dist/dom/swipe.js.map +1 -0
  113. package/dist/dom/targets.d.ts +45 -0
  114. package/dist/dom/targets.d.ts.map +1 -0
  115. package/dist/dom/targets.js +70 -0
  116. package/dist/dom/targets.js.map +1 -0
  117. package/dist/dom/track-box.d.ts +61 -0
  118. package/dist/dom/track-box.d.ts.map +1 -0
  119. package/dist/dom/track-box.js +131 -0
  120. package/dist/dom/track-box.js.map +1 -0
  121. package/dist/events/active-element.d.ts +15 -0
  122. package/dist/events/active-element.d.ts.map +1 -0
  123. package/dist/events/active-element.js +33 -0
  124. package/dist/events/active-element.js.map +1 -0
  125. package/dist/events/hotkeys.d.ts +22 -0
  126. package/dist/events/hotkeys.d.ts.map +1 -0
  127. package/dist/events/hotkeys.js +56 -0
  128. package/dist/events/hotkeys.js.map +1 -0
  129. package/dist/events/idle.d.ts +29 -0
  130. package/dist/events/idle.d.ts.map +1 -0
  131. package/dist/events/idle.js +51 -0
  132. package/dist/events/idle.js.map +1 -0
  133. package/dist/events/index.d.ts +9 -0
  134. package/dist/events/index.js +10 -0
  135. package/dist/{input-modality-BY-bSrEc.d.mts → events/input-modality.d.ts} +9 -12
  136. package/dist/events/input-modality.d.ts.map +1 -0
  137. package/dist/{input-modality-BXD383jg.mjs → events/input-modality.js} +3 -4
  138. package/dist/events/input-modality.js.map +1 -0
  139. package/dist/events/keyboard.d.ts +30 -0
  140. package/dist/events/keyboard.d.ts.map +1 -0
  141. package/dist/events/keyboard.js +55 -0
  142. package/dist/events/keyboard.js.map +1 -0
  143. package/dist/events/pointer.d.ts +15 -0
  144. package/dist/events/pointer.d.ts.map +1 -0
  145. package/dist/events/pointer.js +28 -0
  146. package/dist/events/pointer.js.map +1 -0
  147. package/dist/events/scroll.d.ts +16 -0
  148. package/dist/events/scroll.d.ts.map +1 -0
  149. package/dist/events/scroll.js +29 -0
  150. package/dist/events/scroll.js.map +1 -0
  151. package/dist/events/visibility.d.ts +25 -0
  152. package/dist/events/visibility.d.ts.map +1 -0
  153. package/dist/events/visibility.js +28 -0
  154. package/dist/events/visibility.js.map +1 -0
  155. package/dist/events/window-size.d.ts +30 -0
  156. package/dist/events/window-size.d.ts.map +1 -0
  157. package/dist/events/window-size.js +63 -0
  158. package/dist/events/window-size.js.map +1 -0
  159. package/dist/index.d.ts +9 -0
  160. package/dist/index.js +10 -0
  161. package/dist/interaction/bundle-behavior.d.ts +37 -0
  162. package/dist/interaction/bundle-behavior.d.ts.map +1 -0
  163. package/dist/interaction/bundle-behavior.js +34 -0
  164. package/dist/interaction/bundle-behavior.js.map +1 -0
  165. package/dist/interaction/dismiss-layer.d.ts +100 -0
  166. package/dist/interaction/dismiss-layer.d.ts.map +1 -0
  167. package/dist/interaction/dismiss-layer.js +140 -0
  168. package/dist/interaction/dismiss-layer.js.map +1 -0
  169. package/dist/interaction/editable-text.d.ts +13 -0
  170. package/dist/interaction/editable-text.d.ts.map +1 -0
  171. package/dist/interaction/editable-text.js +17 -0
  172. package/dist/interaction/editable-text.js.map +1 -0
  173. package/dist/interaction/focus-scope.d.ts +21 -0
  174. package/dist/interaction/focus-scope.d.ts.map +1 -0
  175. package/dist/interaction/focus-scope.js +25 -0
  176. package/dist/interaction/focus-scope.js.map +1 -0
  177. package/dist/interaction/focus-visible.d.ts +9 -0
  178. package/dist/interaction/focus-visible.d.ts.map +1 -0
  179. package/dist/interaction/focus-visible.js +10 -0
  180. package/dist/interaction/focus-visible.js.map +1 -0
  181. package/dist/interaction/grid-navigation.d.ts +73 -0
  182. package/dist/interaction/grid-navigation.d.ts.map +1 -0
  183. package/dist/interaction/grid-navigation.js +137 -0
  184. package/dist/interaction/grid-navigation.js.map +1 -0
  185. package/dist/interaction/index.d.ts +21 -0
  186. package/dist/interaction/index.js +21 -0
  187. package/dist/interaction/layers.d.ts +12 -0
  188. package/dist/interaction/layers.d.ts.map +1 -0
  189. package/dist/interaction/layers.js +14 -0
  190. package/dist/interaction/layers.js.map +1 -0
  191. package/dist/interaction/list-navigation.d.ts +105 -0
  192. package/dist/interaction/list-navigation.d.ts.map +1 -0
  193. package/dist/interaction/list-navigation.js +168 -0
  194. package/dist/interaction/list-navigation.js.map +1 -0
  195. package/dist/interaction/live-announce.d.ts +70 -0
  196. package/dist/interaction/live-announce.d.ts.map +1 -0
  197. package/dist/interaction/live-announce.js +115 -0
  198. package/dist/interaction/live-announce.js.map +1 -0
  199. package/dist/interaction/long-press.d.ts +102 -0
  200. package/dist/interaction/long-press.d.ts.map +1 -0
  201. package/dist/interaction/long-press.js +115 -0
  202. package/dist/interaction/long-press.js.map +1 -0
  203. package/dist/interaction/move.d.ts +10 -0
  204. package/dist/interaction/move.d.ts.map +1 -0
  205. package/dist/interaction/move.js +17 -0
  206. package/dist/interaction/move.js.map +1 -0
  207. package/dist/interaction/overlay.d.ts +45 -0
  208. package/dist/interaction/overlay.d.ts.map +1 -0
  209. package/dist/interaction/overlay.js +57 -0
  210. package/dist/interaction/overlay.js.map +1 -0
  211. package/dist/interaction/placing.d.ts +86 -0
  212. package/dist/interaction/placing.d.ts.map +1 -0
  213. package/dist/interaction/placing.js +239 -0
  214. package/dist/interaction/placing.js.map +1 -0
  215. package/dist/interaction/pointer-drag.d.ts +23 -0
  216. package/dist/interaction/pointer-drag.d.ts.map +1 -0
  217. package/dist/interaction/pointer-drag.js +21 -0
  218. package/dist/interaction/pointer-drag.js.map +1 -0
  219. package/dist/interaction/press.d.ts +152 -0
  220. package/dist/interaction/press.d.ts.map +1 -0
  221. package/dist/interaction/press.js +229 -0
  222. package/dist/interaction/press.js.map +1 -0
  223. package/dist/interaction/roving-tabindex.d.ts +85 -0
  224. package/dist/interaction/roving-tabindex.d.ts.map +1 -0
  225. package/dist/interaction/roving-tabindex.js +142 -0
  226. package/dist/interaction/roving-tabindex.js.map +1 -0
  227. package/dist/interaction/selection.d.ts +72 -0
  228. package/dist/interaction/selection.d.ts.map +1 -0
  229. package/dist/interaction/selection.js +129 -0
  230. package/dist/interaction/selection.js.map +1 -0
  231. package/dist/interaction/targets.d.ts +15 -0
  232. package/dist/interaction/targets.d.ts.map +1 -0
  233. package/dist/interaction/targets.js +20 -0
  234. package/dist/interaction/targets.js.map +1 -0
  235. package/dist/interaction/tree-navigation.d.ts +111 -0
  236. package/dist/interaction/tree-navigation.d.ts.map +1 -0
  237. package/dist/interaction/tree-navigation.js +207 -0
  238. package/dist/interaction/tree-navigation.js.map +1 -0
  239. package/dist/interaction/typeahead.d.ts +73 -0
  240. package/dist/interaction/typeahead.d.ts.map +1 -0
  241. package/dist/interaction/typeahead.js +113 -0
  242. package/dist/interaction/typeahead.js.map +1 -0
  243. package/dist/internal.d.ts +16 -0
  244. package/dist/internal.d.ts.map +1 -0
  245. package/dist/{internal-DP-xLKbT.mjs → internal.js} +8 -7
  246. package/dist/internal.js.map +1 -0
  247. package/dist/media/breakpoints.d.ts +37 -0
  248. package/dist/media/breakpoints.d.ts.map +1 -0
  249. package/dist/media/breakpoints.js +64 -0
  250. package/dist/media/breakpoints.js.map +1 -0
  251. package/dist/media/index.d.ts +3 -0
  252. package/dist/media/index.js +4 -0
  253. package/dist/media/mediaquery.d.ts +40 -0
  254. package/dist/media/mediaquery.d.ts.map +1 -0
  255. package/dist/media/mediaquery.js +42 -0
  256. package/dist/media/mediaquery.js.map +1 -0
  257. package/dist/media/platform.d.ts +30 -0
  258. package/dist/media/platform.d.ts.map +1 -0
  259. package/dist/media/platform.js +50 -0
  260. package/dist/media/platform.js.map +1 -0
  261. package/dist/motion/index.d.ts +5 -0
  262. package/dist/motion/index.js +5 -0
  263. package/dist/motion/motion.d.ts +16 -0
  264. package/dist/motion/motion.d.ts.map +1 -0
  265. package/dist/motion/motion.js +25 -0
  266. package/dist/motion/motion.js.map +1 -0
  267. package/dist/motion/presence.d.ts +37 -0
  268. package/dist/motion/presence.d.ts.map +1 -0
  269. package/dist/motion/presence.js +65 -0
  270. package/dist/motion/presence.js.map +1 -0
  271. package/dist/motion/spring.d.ts +50 -0
  272. package/dist/motion/spring.d.ts.map +1 -0
  273. package/dist/motion/spring.js +92 -0
  274. package/dist/motion/spring.js.map +1 -0
  275. package/dist/motion/tween.d.ts +44 -0
  276. package/dist/motion/tween.d.ts.map +1 -0
  277. package/dist/motion/tween.js +65 -0
  278. package/dist/motion/tween.js.map +1 -0
  279. package/dist/net/broadcast.d.ts +39 -0
  280. package/dist/net/broadcast.d.ts.map +1 -0
  281. package/dist/net/broadcast.js +73 -0
  282. package/dist/net/broadcast.js.map +1 -0
  283. package/dist/net/index.d.ts +5 -0
  284. package/dist/net/index.js +6 -0
  285. package/dist/net/online.d.ts +24 -0
  286. package/dist/net/online.d.ts.map +1 -0
  287. package/dist/net/online.js +26 -0
  288. package/dist/net/online.js.map +1 -0
  289. package/dist/net/sharedHost.d.ts +64 -0
  290. package/dist/net/sharedHost.d.ts.map +1 -0
  291. package/dist/net/sharedHost.js +124 -0
  292. package/dist/net/sharedHost.js.map +1 -0
  293. package/dist/net/sse.d.ts +115 -0
  294. package/dist/net/sse.d.ts.map +1 -0
  295. package/dist/net/sse.js +138 -0
  296. package/dist/net/sse.js.map +1 -0
  297. package/dist/net/websocket.d.ts +172 -0
  298. package/dist/net/websocket.d.ts.map +1 -0
  299. package/dist/net/websocket.js +199 -0
  300. package/dist/net/websocket.js.map +1 -0
  301. package/dist/observers/bounds.d.ts +24 -0
  302. package/dist/observers/bounds.d.ts.map +1 -0
  303. package/dist/observers/bounds.js +51 -0
  304. package/dist/observers/bounds.js.map +1 -0
  305. package/dist/observers/index.d.ts +4 -0
  306. package/dist/observers/index.js +5 -0
  307. package/dist/observers/intersection.d.ts +18 -0
  308. package/dist/observers/intersection.d.ts.map +1 -0
  309. package/dist/observers/intersection.js +33 -0
  310. package/dist/observers/intersection.js.map +1 -0
  311. package/dist/observers/mutation.d.ts +25 -0
  312. package/dist/observers/mutation.d.ts.map +1 -0
  313. package/dist/observers/mutation.js +53 -0
  314. package/dist/observers/mutation.js.map +1 -0
  315. package/dist/observers/resize.d.ts +18 -0
  316. package/dist/observers/resize.d.ts.map +1 -0
  317. package/dist/observers/resize.js +33 -0
  318. package/dist/observers/resize.js.map +1 -0
  319. package/dist/state/history.d.ts +115 -0
  320. package/dist/state/history.d.ts.map +1 -0
  321. package/dist/state/history.js +167 -0
  322. package/dist/state/history.js.map +1 -0
  323. package/dist/state/index.d.ts +6 -0
  324. package/dist/state/index.js +7 -0
  325. package/dist/state/locale.d.ts +27 -0
  326. package/dist/state/locale.d.ts.map +1 -0
  327. package/dist/state/locale.js +25 -0
  328. package/dist/state/locale.js.map +1 -0
  329. package/dist/state/pagination.d.ts +53 -0
  330. package/dist/state/pagination.d.ts.map +1 -0
  331. package/dist/state/pagination.js +72 -0
  332. package/dist/state/pagination.js.map +1 -0
  333. package/dist/state/range.d.ts +9 -0
  334. package/dist/state/range.d.ts.map +1 -0
  335. package/dist/state/range.js +18 -0
  336. package/dist/state/range.js.map +1 -0
  337. package/dist/state/selection.d.ts +47 -0
  338. package/dist/state/selection.d.ts.map +1 -0
  339. package/dist/state/selection.js +39 -0
  340. package/dist/state/selection.js.map +1 -0
  341. package/dist/state/virtual.d.ts +201 -0
  342. package/dist/state/virtual.d.ts.map +1 -0
  343. package/dist/state/{index.mjs → virtual.js} +11 -313
  344. package/dist/state/virtual.js.map +1 -0
  345. package/dist/time/debounce.d.ts +43 -0
  346. package/dist/time/debounce.d.ts.map +1 -0
  347. package/dist/time/debounce.js +65 -0
  348. package/dist/time/debounce.js.map +1 -0
  349. package/dist/time/index.d.ts +6 -0
  350. package/dist/time/index.js +7 -0
  351. package/dist/time/interval.d.ts +37 -0
  352. package/dist/time/interval.d.ts.map +1 -0
  353. package/dist/time/interval.js +52 -0
  354. package/dist/time/interval.js.map +1 -0
  355. package/dist/time/relative.d.ts +8 -0
  356. package/dist/time/relative.d.ts.map +1 -0
  357. package/dist/time/relative.js +27 -0
  358. package/dist/time/relative.js.map +1 -0
  359. package/dist/time/throttle.d.ts +38 -0
  360. package/dist/time/throttle.d.ts.map +1 -0
  361. package/dist/time/throttle.js +39 -0
  362. package/dist/time/throttle.js.map +1 -0
  363. package/dist/time/ticks.d.ts +21 -0
  364. package/dist/time/ticks.d.ts.map +1 -0
  365. package/dist/time/ticks.js +30 -0
  366. package/dist/time/ticks.js.map +1 -0
  367. package/dist/time/timer.d.ts +32 -0
  368. package/dist/time/timer.d.ts.map +1 -0
  369. package/dist/time/timer.js +50 -0
  370. package/dist/time/timer.js.map +1 -0
  371. package/package.json +31 -31
  372. package/dist/device/index.d.mts +0 -345
  373. package/dist/device/index.d.mts.map +0 -1
  374. package/dist/device/index.mjs +0 -498
  375. package/dist/device/index.mjs.map +0 -1
  376. package/dist/dom/index.d.mts +0 -750
  377. package/dist/dom/index.d.mts.map +0 -1
  378. package/dist/dom/index.mjs +0 -1857
  379. package/dist/dom/index.mjs.map +0 -1
  380. package/dist/editable-text-1D31qthY.d.mts +0 -319
  381. package/dist/editable-text-1D31qthY.d.mts.map +0 -1
  382. package/dist/events/index.d.mts +0 -184
  383. package/dist/events/index.d.mts.map +0 -1
  384. package/dist/events/index.mjs +0 -315
  385. package/dist/events/index.mjs.map +0 -1
  386. package/dist/follow-tab-stop-Caog2qg1.mjs +0 -863
  387. package/dist/follow-tab-stop-Caog2qg1.mjs.map +0 -1
  388. package/dist/index-CmmxqSEi.d.mts +0 -149
  389. package/dist/index-CmmxqSEi.d.mts.map +0 -1
  390. package/dist/index.d.mts +0 -12
  391. package/dist/index.mjs +0 -12
  392. package/dist/input-modality-BXD383jg.mjs.map +0 -1
  393. package/dist/input-modality-BY-bSrEc.d.mts.map +0 -1
  394. package/dist/interaction/index.d.mts +0 -1194
  395. package/dist/interaction/index.d.mts.map +0 -1
  396. package/dist/interaction/index.mjs +0 -2012
  397. package/dist/interaction/index.mjs.map +0 -1
  398. package/dist/internal-DP-xLKbT.mjs.map +0 -1
  399. package/dist/media/index.d.mts +0 -109
  400. package/dist/media/index.d.mts.map +0 -1
  401. package/dist/media/index.mjs +0 -149
  402. package/dist/media/index.mjs.map +0 -1
  403. package/dist/motion/index.d.mts +0 -2
  404. package/dist/motion/index.mjs +0 -1
  405. package/dist/motion-DmFDppRn.mjs +0 -240
  406. package/dist/motion-DmFDppRn.mjs.map +0 -1
  407. package/dist/net/index.d.mts +0 -348
  408. package/dist/net/index.d.mts.map +0 -1
  409. package/dist/net/index.mjs +0 -535
  410. package/dist/net/index.mjs.map +0 -1
  411. package/dist/observers/index.d.mts +0 -84
  412. package/dist/observers/index.d.mts.map +0 -1
  413. package/dist/observers/index.mjs +0 -159
  414. package/dist/observers/index.mjs.map +0 -1
  415. package/dist/rolldown-runtime-D7D4PA-g.mjs +0 -13
  416. package/dist/state/index.d.mts +0 -444
  417. package/dist/state/index.d.mts.map +0 -1
  418. package/dist/state/index.mjs.map +0 -1
  419. package/dist/time/index.d.mts +0 -179
  420. package/dist/time/index.d.mts.map +0 -1
  421. package/dist/time/index.mjs +0 -242
  422. package/dist/time/index.mjs.map +0 -1
@@ -0,0 +1,29 @@
1
+ import * as Mount from "foldkit/mount";
2
+ /**
3
+ * The custom property `KeyboardInset` writes on its element: how much of the layout
4
+ * viewport's bottom the on-screen keyboard (or anything else the visual viewport leaves
5
+ * out) covers, in pixels.
6
+ */
7
+ export declare const KEYBOARD_INSET = "--fk-keyboard-inset";
8
+ /**
9
+ * The part of the layout viewport's height below the visual viewport: what the on-screen
10
+ * keyboard covers. Rounded down, since a fraction of a pixel of zoom is no keyboard.
11
+ */
12
+ export declare const keyboardInset: (view: {
13
+ readonly innerHeight: number;
14
+ readonly visualViewport: {
15
+ readonly height: number;
16
+ readonly offsetTop: number;
17
+ } | null;
18
+ }) => number;
19
+ /**
20
+ * The on-screen keyboard's height as a Mount, with no Message and no Model: where it is
21
+ * is the browser's. iOS Safari, and Chrome on Android unless the page asks otherwise,
22
+ * leave the layout viewport as it is when the keyboard opens, so a panel fixed to the
23
+ * screen keeps its height and its bottom under the keys. This writes `KEYBOARD_INSET` on
24
+ * the element, from the visual viewport's size and scroll, for a style to pad or shrink by
25
+ * (`var(--fk-keyboard-inset, 0px)`), and removes it when the element goes. Where there is
26
+ * no visual viewport it writes nothing.
27
+ */
28
+ export declare const KeyboardInset: Mount.MountDefinitionWithArgs<"KeyboardInset", {}, never>;
29
+ //# sourceMappingURL=keyboard-inset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard-inset.d.ts","names":[],"sources":["../../src/dom/keyboard-inset.ts"],"mappings":";;;;;;qBAQa;;;;;qBAMA,gBAAa;WACf;WACA;aAA2B;aAAyB;;;;;;;;;;;;qBAkBlD,eAAa,MAAA"}
@@ -0,0 +1,45 @@
1
+ import { Effect, Schema, Stream } from "effect";
2
+ import * as Mount from "foldkit/mount";
3
+ // src/dom/keyboard-inset.ts
4
+ /**
5
+ * The custom property `KeyboardInset` writes on its element: how much of the layout
6
+ * viewport's bottom the on-screen keyboard (or anything else the visual viewport leaves
7
+ * out) covers, in pixels.
8
+ */
9
+ const KEYBOARD_INSET = "--fk-keyboard-inset";
10
+ /**
11
+ * The part of the layout viewport's height below the visual viewport: what the on-screen
12
+ * keyboard covers. Rounded down, since a fraction of a pixel of zoom is no keyboard.
13
+ */
14
+ const keyboardInset = (view) => view.visualViewport === null ? 0 : Math.max(0, Math.floor(view.innerHeight - view.visualViewport.height - view.visualViewport.offsetTop));
15
+ /**
16
+ * The on-screen keyboard's height as a Mount, with no Message and no Model: where it is
17
+ * is the browser's. iOS Safari, and Chrome on Android unless the page asks otherwise,
18
+ * leave the layout viewport as it is when the keyboard opens, so a panel fixed to the
19
+ * screen keeps its height and its bottom under the keys. This writes `KEYBOARD_INSET` on
20
+ * the element, from the visual viewport's size and scroll, for a style to pad or shrink by
21
+ * (`var(--fk-keyboard-inset, 0px)`), and removes it when the element goes. Where there is
22
+ * no visual viewport it writes nothing.
23
+ */
24
+ const KeyboardInset = Mount.defineStream("KeyboardInset", {
25
+ messages: [Schema.Never],
26
+ args: {},
27
+ execute: ({ element }) => Stream.callback(() => Effect.acquireRelease(Effect.sync(() => {
28
+ const view = element.ownerDocument.defaultView;
29
+ const viewport = view?.visualViewport;
30
+ if (!(element instanceof HTMLElement) || view === null || view === void 0 || viewport === null || viewport === void 0) return () => {};
31
+ const target = element;
32
+ const measure = () => target.style.setProperty(KEYBOARD_INSET, `${keyboardInset(view)}px`);
33
+ measure();
34
+ viewport.addEventListener("resize", measure);
35
+ viewport.addEventListener("scroll", measure);
36
+ return () => {
37
+ viewport.removeEventListener("resize", measure);
38
+ viewport.removeEventListener("scroll", measure);
39
+ target.style.removeProperty(KEYBOARD_INSET);
40
+ };
41
+ }), (release) => Effect.sync(release)))
42
+ });
43
+ export { KEYBOARD_INSET, KeyboardInset, keyboardInset };
44
+
45
+ //# sourceMappingURL=keyboard-inset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard-inset.js","names":[],"sources":["../../src/dom/keyboard-inset.ts"],"sourcesContent":["import { Effect, Schema, Stream } from 'effect'\nimport * as Mount from 'foldkit/mount'\n\n/**\n * The custom property `KeyboardInset` writes on its element: how much of the layout\n * viewport's bottom the on-screen keyboard (or anything else the visual viewport leaves\n * out) covers, in pixels.\n */\nexport const KEYBOARD_INSET = '--fk-keyboard-inset'\n\n/**\n * The part of the layout viewport's height below the visual viewport: what the on-screen\n * keyboard covers. Rounded down, since a fraction of a pixel of zoom is no keyboard.\n */\nexport const keyboardInset = (view: {\n readonly innerHeight: number\n readonly visualViewport: { readonly height: number; readonly offsetTop: number } | null\n}): number =>\n view.visualViewport === null\n ? 0\n : Math.max(\n 0,\n Math.floor(view.innerHeight - view.visualViewport.height - view.visualViewport.offsetTop),\n )\n\n/**\n * The on-screen keyboard's height as a Mount, with no Message and no Model: where it is\n * is the browser's. iOS Safari, and Chrome on Android unless the page asks otherwise,\n * leave the layout viewport as it is when the keyboard opens, so a panel fixed to the\n * screen keeps its height and its bottom under the keys. This writes `KEYBOARD_INSET` on\n * the element, from the visual viewport's size and scroll, for a style to pad or shrink by\n * (`var(--fk-keyboard-inset, 0px)`), and removes it when the element goes. Where there is\n * no visual viewport it writes nothing.\n */\nexport const KeyboardInset = Mount.defineStream('KeyboardInset', {\n messages: [Schema.Never],\n args: {},\n execute: ({ element }) =>\n Stream.callback<never>(() =>\n Effect.acquireRelease(\n Effect.sync(() => {\n const view = element.ownerDocument.defaultView\n const viewport = view?.visualViewport\n if (\n !(element instanceof HTMLElement) ||\n view === null ||\n view === undefined ||\n viewport === null ||\n viewport === undefined\n ) {\n return () => {}\n }\n const target = element\n const measure = () => target.style.setProperty(KEYBOARD_INSET, `${keyboardInset(view)}px`)\n measure()\n viewport.addEventListener('resize', measure)\n viewport.addEventListener('scroll', measure)\n return () => {\n viewport.removeEventListener('resize', measure)\n viewport.removeEventListener('scroll', measure)\n target.style.removeProperty(KEYBOARD_INSET)\n }\n }),\n release => Effect.sync(release),\n ),\n ),\n})\n"],"mappings":";;;;;;;;AAQA,MAAa,iBAAiB;;;;;AAM9B,MAAa,iBAAiB,SAI5B,KAAK,mBAAmB,OACpB,IACA,KAAK,IACH,GACA,KAAK,MAAM,KAAK,cAAc,KAAK,eAAe,SAAS,KAAK,eAAe,SAAS,CAC1F;;;;;;;;;;AAWN,MAAa,gBAAgB,MAAM,aAAa,iBAAiB;CAC/D,UAAU,CAAC,OAAO,KAAK;CACvB,MAAM,CAAC;CACP,UAAU,EAAE,cACV,OAAO,eACL,OAAO,eACL,OAAO,WAAW;EAChB,MAAM,OAAO,QAAQ,cAAc;EACnC,MAAM,WAAW,MAAM;EACvB,IACE,EAAE,mBAAmB,gBACrB,SAAS,QACT,SAAS,KAAA,KACT,aAAa,QACb,aAAa,KAAA,GAEb,aAAa,CAAC;EAEhB,MAAM,SAAS;EACf,MAAM,gBAAgB,OAAO,MAAM,YAAY,gBAAgB,GAAG,cAAc,IAAI,EAAE,GAAG;EACzF,QAAQ;EACR,SAAS,iBAAiB,UAAU,OAAO;EAC3C,SAAS,iBAAiB,UAAU,OAAO;EAC3C,aAAa;GACX,SAAS,oBAAoB,UAAU,OAAO;GAC9C,SAAS,oBAAoB,UAAU,OAAO;GAC9C,OAAO,MAAM,eAAe,cAAc;EAC5C;CACF,CAAC,IACD,YAAW,OAAO,KAAK,OAAO,CAChC,CACF;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import * as Mount from "foldkit/mount";
2
+ /** Locks the document's scroll while the element is mounted; nested locks release with the last. */
3
+ export declare const ScrollLock: Mount.MountDefinitionNoArgs<"ScrollLock", never>;
4
+ /** Makes everything outside the element inert while it is mounted, and restores it after. */
5
+ export declare const HideOutside: Mount.MountDefinitionNoArgs<"HideOutside", never>;
6
+ //# sourceMappingURL=layers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layers.d.ts","names":[],"sources":["../../src/dom/layers.ts"],"mappings":";;qBAgBa,YAAU,MAAA;;qBAWV,aAAW,MAAA"}
@@ -0,0 +1,35 @@
1
+ import { Effect, Schema, Stream } from "effect";
2
+ import * as Mount from "foldkit/mount";
3
+ import * as Dom from "foldkit/dom";
4
+ // src/dom/layers.ts
5
+ /**
6
+ * Two Mounts over Foldkit's own DOM helpers, for an overlay that is not a
7
+ * native `<dialog>` or `popover`:
8
+ *
9
+ * - `ScrollLock` locks the document's scroll while mounted. Foldkit's lock is
10
+ * refcounted, so nested overlays release it only when the last one goes.
11
+ * - `HideOutside` marks everything outside the element inert while mounted,
12
+ * through `Dom.inertOthers`, keyed by an id this Mount mints.
13
+ *
14
+ * Both emit no Messages; they are element lifecycle.
15
+ */
16
+ /** Locks the document's scroll while the element is mounted; nested locks release with the last. */
17
+ const ScrollLock = Mount.defineStream("ScrollLock", {
18
+ messages: [Schema.Never],
19
+ execute: () => Stream.callback(() => Effect.acquireRelease(Dom.lockScroll, () => Dom.unlockScroll))
20
+ });
21
+ const HIDE_OUTSIDE_ATTRIBUTE = "data-foldkit-plus-hide-outside";
22
+ let minted = 0;
23
+ /** Makes everything outside the element inert while it is mounted, and restores it after. */
24
+ const HideOutside = Mount.defineStream("HideOutside", {
25
+ messages: [Schema.Never],
26
+ execute: ({ element }) => Stream.callback(() => Effect.acquireRelease(Effect.gen(function* () {
27
+ const id = `hide-outside-${minted += 1}`;
28
+ element.setAttribute(HIDE_OUTSIDE_ATTRIBUTE, id);
29
+ yield* Dom.inertOthers(id, [`[${HIDE_OUTSIDE_ATTRIBUTE}="${id}"]`]);
30
+ return id;
31
+ }), (id) => Effect.andThen(Dom.restoreInert(id), () => Effect.sync(() => element.removeAttribute(HIDE_OUTSIDE_ATTRIBUTE)))))
32
+ });
33
+ export { HideOutside, ScrollLock };
34
+
35
+ //# sourceMappingURL=layers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layers.js","names":[],"sources":["../../src/dom/layers.ts"],"sourcesContent":["/**\n * Two Mounts over Foldkit's own DOM helpers, for an overlay that is not a\n * native `<dialog>` or `popover`:\n *\n * - `ScrollLock` locks the document's scroll while mounted. Foldkit's lock is\n * refcounted, so nested overlays release it only when the last one goes.\n * - `HideOutside` marks everything outside the element inert while mounted,\n * through `Dom.inertOthers`, keyed by an id this Mount mints.\n *\n * Both emit no Messages; they are element lifecycle.\n */\nimport { Effect, Schema, Stream } from 'effect'\nimport * as Dom from 'foldkit/dom'\nimport * as Mount from 'foldkit/mount'\n\n/** Locks the document's scroll while the element is mounted; nested locks release with the last. */\nexport const ScrollLock = Mount.defineStream('ScrollLock', {\n messages: [Schema.Never],\n execute: () =>\n Stream.callback<never>(() => Effect.acquireRelease(Dom.lockScroll, () => Dom.unlockScroll)),\n})\n\nconst HIDE_OUTSIDE_ATTRIBUTE = 'data-foldkit-plus-hide-outside'\n\nlet minted = 0\n\n/** Makes everything outside the element inert while it is mounted, and restores it after. */\nexport const HideOutside = Mount.defineStream('HideOutside', {\n messages: [Schema.Never],\n execute: ({ element }) =>\n Stream.callback<never>(() =>\n Effect.acquireRelease(\n Effect.gen(function* () {\n // A per-mount id: Foldkit keys the inert set by it, so two overlays\n // restore independently. The attribute is how the element is found.\n const id = `hide-outside-${(minted += 1)}`\n element.setAttribute(HIDE_OUTSIDE_ATTRIBUTE, id)\n yield* Dom.inertOthers(id, [`[${HIDE_OUTSIDE_ATTRIBUTE}=\"${id}\"]`])\n return id\n }),\n id =>\n Effect.andThen(Dom.restoreInert(id), () =>\n Effect.sync(() => element.removeAttribute(HIDE_OUTSIDE_ATTRIBUTE)),\n ),\n ),\n ),\n})\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,MAAa,aAAa,MAAM,aAAa,cAAc;CACzD,UAAU,CAAC,OAAO,KAAK;CACvB,eACE,OAAO,eAAsB,OAAO,eAAe,IAAI,kBAAkB,IAAI,YAAY,CAAC;AAC9F,CAAC;AAED,MAAM,yBAAyB;AAE/B,IAAI,SAAS;;AAGb,MAAa,cAAc,MAAM,aAAa,eAAe;CAC3D,UAAU,CAAC,OAAO,KAAK;CACvB,UAAU,EAAE,cACV,OAAO,eACL,OAAO,eACL,OAAO,IAAI,aAAa;EAGtB,MAAM,KAAK,gBAAiB,UAAU;EACtC,QAAQ,aAAa,wBAAwB,EAAE;EAC/C,OAAO,IAAI,YAAY,IAAI,CAAC,IAAI,uBAAuB,IAAI,GAAG,GAAG,CAAC;EAClE,OAAO;CACT,CAAC,IACD,OACE,OAAO,QAAQ,IAAI,aAAa,EAAE,SAChC,OAAO,WAAW,QAAQ,gBAAgB,sBAAsB,CAAC,CACnE,CACJ,CACF;AACJ,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { Schema } from "effect";
2
+ import * as Mount from "foldkit/mount";
3
+ /** The custom properties `Measure` writes for a target named `name`. */
4
+ export declare const measured: (name: string) => {
5
+ readonly x: `--fk-${string}-x`;
6
+ readonly y: `--fk-${string}-y`;
7
+ readonly w: `--fk-${string}-w`;
8
+ readonly h: `--fk-${string}-h`;
9
+ readonly display: `--fk-${string}-display`;
10
+ /**
11
+ * `1` for the measure that finds the mark on another element than the
12
+ * last, `0` for any other (the layout moved or resized the same one, or
13
+ * it is the first found): an overlay that glides to a new mark scales its
14
+ * duration by it, so it keeps to its element as the layout settles.
15
+ */
16
+ readonly moving: `--fk-${string}-moving`;
17
+ };
18
+ /**
19
+ * Measures marked elements as a Mount, for a view to draw something over them,
20
+ * such as an editor's selection outline, with no Message and no Model: where
21
+ * an element is, is presentation, known to the DOM and to no transition.
22
+ *
23
+ * For each named target, the first element in the mounted one's subtree that
24
+ * matches its selector is measured relative to the mounted element's scroll
25
+ * box, which is what an absolutely placed child of it is laid out in. The
26
+ * mounted element gets `--fk-<name>-x`, `-y`, `-w` and `-h` in pixels, and
27
+ * `--fk-<name>-display`: `block` while a target is found, `none` while none is,
28
+ * and `--fk-<name>-moving` (see `measured`).
29
+ *
30
+ * It measures again when the subtree changes (a selection moves) or the
31
+ * mounted element or a measured one changes size, in the frame the change is
32
+ * drawn in; and, at most once a frame, when the mounted element scrolls, the
33
+ * window resizes, an image or a font inside loads, and on every frame of a
34
+ * transition or an animation inside. What moves a target by any other way,
35
+ * such as a stylesheet added that shifts it without resizing it, is seen at
36
+ * the next of these.
37
+ */
38
+ export declare const Measure: Mount.MountDefinitionWithArgs<"Measure", {
39
+ /** Each target by name, as a selector within the element: `{ selected: '[aria-selected="true"]' }`. */
40
+ targets: Schema.$Record<Schema.String, Schema.String>;
41
+ }, never>;
42
+ //# sourceMappingURL=measure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measure.d.ts","names":[],"sources":["../../src/dom/measure.ts"],"mappings":";;;qBAIa,WAAQ;WAEjB;WACA;WACA;WACA;WACA;;;;;;;WAOA;;;;;;;;;;;;;;;;;;;;;;qBAuBS,SAAO,MAAA"}
@@ -0,0 +1,123 @@
1
+ import { Effect, Schema, Stream } from "effect";
2
+ import * as Mount from "foldkit/mount";
3
+ // src/dom/measure.ts
4
+ /** The custom properties `Measure` writes for a target named `name`. */
5
+ const measured = (name) => ({
6
+ x: `--fk-${name}-x`,
7
+ y: `--fk-${name}-y`,
8
+ w: `--fk-${name}-w`,
9
+ h: `--fk-${name}-h`,
10
+ display: `--fk-${name}-display`,
11
+ /**
12
+ * `1` for the measure that finds the mark on another element than the
13
+ * last, `0` for any other (the layout moved or resized the same one, or
14
+ * it is the first found): an overlay that glides to a new mark scales its
15
+ * duration by it, so it keeps to its element as the layout settles.
16
+ */
17
+ moving: `--fk-${name}-moving`
18
+ });
19
+ /**
20
+ * Measures marked elements as a Mount, for a view to draw something over them,
21
+ * such as an editor's selection outline, with no Message and no Model: where
22
+ * an element is, is presentation, known to the DOM and to no transition.
23
+ *
24
+ * For each named target, the first element in the mounted one's subtree that
25
+ * matches its selector is measured relative to the mounted element's scroll
26
+ * box, which is what an absolutely placed child of it is laid out in. The
27
+ * mounted element gets `--fk-<name>-x`, `-y`, `-w` and `-h` in pixels, and
28
+ * `--fk-<name>-display`: `block` while a target is found, `none` while none is,
29
+ * and `--fk-<name>-moving` (see `measured`).
30
+ *
31
+ * It measures again when the subtree changes (a selection moves) or the
32
+ * mounted element or a measured one changes size, in the frame the change is
33
+ * drawn in; and, at most once a frame, when the mounted element scrolls, the
34
+ * window resizes, an image or a font inside loads, and on every frame of a
35
+ * transition or an animation inside. What moves a target by any other way,
36
+ * such as a stylesheet added that shifts it without resizing it, is seen at
37
+ * the next of these.
38
+ */
39
+ const Measure = Mount.defineStream("Measure", {
40
+ messages: [Schema.Never],
41
+ args: {
42
+ /** Each target by name, as a selector within the element: `{ selected: '[aria-selected="true"]' }`. */
43
+ targets: Schema.Record(Schema.String, Schema.String) },
44
+ execute: ({ element, targets }) => Stream.callback(() => Effect.acquireRelease(Effect.sync(() => {
45
+ const container = element;
46
+ const names = Object.keys(targets);
47
+ let watched = [];
48
+ const last = /* @__PURE__ */ new Map();
49
+ let frame;
50
+ let animating = false;
51
+ const measure = () => {
52
+ if (frame !== void 0) cancelAnimationFrame(frame);
53
+ frame = void 0;
54
+ const box = container.getBoundingClientRect();
55
+ const found = [];
56
+ for (const name of names) {
57
+ const property = measured(name);
58
+ const target = container.querySelector(targets[name]);
59
+ if (target === null) {
60
+ container.style.setProperty(property.display, "none");
61
+ continue;
62
+ }
63
+ found.push(target);
64
+ const previous = last.get(name);
65
+ last.set(name, target);
66
+ const rect = target.getBoundingClientRect();
67
+ const x = rect.left - box.left - container.clientLeft + container.scrollLeft;
68
+ const y = rect.top - box.top - container.clientTop + container.scrollTop;
69
+ container.style.setProperty(property.x, `${x}px`);
70
+ container.style.setProperty(property.y, `${y}px`);
71
+ container.style.setProperty(property.w, `${rect.width}px`);
72
+ container.style.setProperty(property.h, `${rect.height}px`);
73
+ container.style.setProperty(property.display, "block");
74
+ container.style.setProperty(property.moving, previous === void 0 || previous === target ? "0" : "1");
75
+ }
76
+ if (found.length !== watched.length || found.some((each, at) => each !== watched[at])) {
77
+ for (const each of watched) sizes.unobserve(each);
78
+ for (const each of found) sizes.observe(each);
79
+ watched = found;
80
+ }
81
+ if (animating) {
82
+ animating = container.getAnimations({ subtree: true }).some((animation) => animation.playState === "running");
83
+ if (animating) soon();
84
+ }
85
+ };
86
+ const soon = () => {
87
+ if (frame === void 0) frame = requestAnimationFrame(measure);
88
+ };
89
+ const moving = () => {
90
+ animating = true;
91
+ soon();
92
+ };
93
+ const changes = new MutationObserver(measure);
94
+ const sizes = new ResizeObserver(measure);
95
+ document.fonts.addEventListener("loadingdone", soon);
96
+ changes.observe(container, {
97
+ subtree: true,
98
+ childList: true,
99
+ attributes: true
100
+ });
101
+ sizes.observe(container);
102
+ container.addEventListener("scroll", soon, { passive: true });
103
+ window.addEventListener("resize", soon);
104
+ container.addEventListener("load", soon, { capture: true });
105
+ container.addEventListener("transitionrun", moving);
106
+ container.addEventListener("animationstart", moving);
107
+ measure();
108
+ return () => {
109
+ if (frame !== void 0) cancelAnimationFrame(frame);
110
+ changes.disconnect();
111
+ sizes.disconnect();
112
+ container.removeEventListener("scroll", soon);
113
+ window.removeEventListener("resize", soon);
114
+ container.removeEventListener("load", soon, { capture: true });
115
+ document.fonts.removeEventListener("loadingdone", soon);
116
+ container.removeEventListener("transitionrun", moving);
117
+ container.removeEventListener("animationstart", moving);
118
+ };
119
+ }), (stop) => Effect.sync(stop)))
120
+ });
121
+ export { Measure, measured };
122
+
123
+ //# sourceMappingURL=measure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measure.js","names":[],"sources":["../../src/dom/measure.ts"],"sourcesContent":["import { Effect, Schema, Stream } from 'effect'\nimport * as Mount from 'foldkit/mount'\n\n/** The custom properties `Measure` writes for a target named `name`. */\nexport const measured = (name: string) =>\n ({\n x: `--fk-${name}-x`,\n y: `--fk-${name}-y`,\n w: `--fk-${name}-w`,\n h: `--fk-${name}-h`,\n display: `--fk-${name}-display`,\n /**\n * `1` for the measure that finds the mark on another element than the\n * last, `0` for any other (the layout moved or resized the same one, or\n * it is the first found): an overlay that glides to a new mark scales its\n * duration by it, so it keeps to its element as the layout settles.\n */\n moving: `--fk-${name}-moving`,\n }) as const\n\n/**\n * Measures marked elements as a Mount, for a view to draw something over them,\n * such as an editor's selection outline, with no Message and no Model: where\n * an element is, is presentation, known to the DOM and to no transition.\n *\n * For each named target, the first element in the mounted one's subtree that\n * matches its selector is measured relative to the mounted element's scroll\n * box, which is what an absolutely placed child of it is laid out in. The\n * mounted element gets `--fk-<name>-x`, `-y`, `-w` and `-h` in pixels, and\n * `--fk-<name>-display`: `block` while a target is found, `none` while none is,\n * and `--fk-<name>-moving` (see `measured`).\n *\n * It measures again when the subtree changes (a selection moves) or the\n * mounted element or a measured one changes size, in the frame the change is\n * drawn in; and, at most once a frame, when the mounted element scrolls, the\n * window resizes, an image or a font inside loads, and on every frame of a\n * transition or an animation inside. What moves a target by any other way,\n * such as a stylesheet added that shifts it without resizing it, is seen at\n * the next of these.\n */\nexport const Measure = Mount.defineStream('Measure', {\n messages: [Schema.Never],\n args: {\n /** Each target by name, as a selector within the element: `{ selected: '[aria-selected=\"true\"]' }`. */\n targets: Schema.Record(Schema.String, Schema.String),\n },\n execute: ({ element, targets }) =>\n Stream.callback<never>(() =>\n Effect.acquireRelease(\n Effect.sync(() => {\n const container = element as HTMLElement\n const names = Object.keys(targets)\n let watched: ReadonlyArray<Element> = []\n // The element each target was last measured on, to tell a new mark from a moved layout.\n const last = new Map<string, Element>()\n let frame: number | undefined\n // Whether a transition or an animation may be moving something, until one frame finds none.\n let animating = false\n\n const measure = () => {\n if (frame !== undefined) cancelAnimationFrame(frame)\n frame = undefined\n const box = container.getBoundingClientRect()\n const found: Array<Element> = []\n for (const name of names) {\n const property = measured(name)\n const target = container.querySelector(targets[name]!)\n if (target === null) {\n container.style.setProperty(property.display, 'none')\n continue\n }\n found.push(target)\n const previous = last.get(name)\n last.set(name, target)\n const rect = target.getBoundingClientRect()\n // Relative to the scroll box: where the content is, not where the viewport shows it.\n const x = rect.left - box.left - container.clientLeft + container.scrollLeft\n const y = rect.top - box.top - container.clientTop + container.scrollTop\n container.style.setProperty(property.x, `${x}px`)\n container.style.setProperty(property.y, `${y}px`)\n container.style.setProperty(property.w, `${rect.width}px`)\n container.style.setProperty(property.h, `${rect.height}px`)\n container.style.setProperty(property.display, 'block')\n container.style.setProperty(\n property.moving,\n previous === undefined || previous === target ? '0' : '1',\n )\n }\n // A measured element that changes size, as an image loading does, is measured again.\n if (found.length !== watched.length || found.some((each, at) => each !== watched[at])) {\n for (const each of watched) sizes.unobserve(each)\n for (const each of found) sizes.observe(each)\n watched = found\n }\n if (animating) {\n // Asked each frame rather than counted: an element removed mid-transition ends none.\n animating = container\n .getAnimations({ subtree: true })\n .some(animation => animation.playState === 'running')\n if (animating) soon()\n }\n }\n const soon = () => {\n if (frame === undefined) frame = requestAnimationFrame(measure)\n }\n const moving = () => {\n animating = true\n soon()\n }\n\n // A change is measured as its records arrive, before the frame it is drawn in is\n // painted, so a box never shows one frame on the element it has left.\n const changes = new MutationObserver(measure)\n // Made, and the fonts listened to, before anything observes: where one is\n // missing (jsdom has neither a ResizeObserver nor `document.fonts`), the Mount\n // fails with nothing attached to call `measure`. A size is measured as it is\n // observed, after layout and before paint: a frame later, a popup whose width\n // settled as it opened showed its marker at the old width, past its edge.\n const sizes = new ResizeObserver(measure)\n document.fonts.addEventListener('loadingdone', soon)\n // Its own properties change the container's style too, but writing the same\n // values again records nothing, so a measure that changed nothing rests.\n changes.observe(container, { subtree: true, childList: true, attributes: true })\n sizes.observe(container)\n container.addEventListener('scroll', soon, { passive: true })\n window.addEventListener('resize', soon)\n // `load` does not bubble, so it is caught on the way down.\n container.addEventListener('load', soon, { capture: true })\n container.addEventListener('transitionrun', moving)\n container.addEventListener('animationstart', moving)\n measure()\n return () => {\n if (frame !== undefined) cancelAnimationFrame(frame)\n changes.disconnect()\n sizes.disconnect()\n container.removeEventListener('scroll', soon)\n window.removeEventListener('resize', soon)\n container.removeEventListener('load', soon, { capture: true })\n document.fonts.removeEventListener('loadingdone', soon)\n container.removeEventListener('transitionrun', moving)\n container.removeEventListener('animationstart', moving)\n }\n }),\n stop => Effect.sync(stop),\n ),\n ),\n})\n"],"mappings":";;;;AAIA,MAAa,YAAY,UACtB;CACC,GAAG,QAAQ,KAAK;CAChB,GAAG,QAAQ,KAAK;CAChB,GAAG,QAAQ,KAAK;CAChB,GAAG,QAAQ,KAAK;CAChB,SAAS,QAAQ,KAAK;;;;;;;CAOtB,QAAQ,QAAQ,KAAK;AACvB;;;;;;;;;;;;;;;;;;;;;AAsBF,MAAa,UAAU,MAAM,aAAa,WAAW;CACnD,UAAU,CAAC,OAAO,KAAK;CACvB,MAAM;;AAEJ,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO,MAAM,EACrD;CACA,UAAU,EAAE,SAAS,cACnB,OAAO,eACL,OAAO,eACL,OAAO,WAAW;EAChB,MAAM,YAAY;EAClB,MAAM,QAAQ,OAAO,KAAK,OAAO;EACjC,IAAI,UAAkC,CAAC;EAEvC,MAAM,uBAAO,IAAI,IAAqB;EACtC,IAAI;EAEJ,IAAI,YAAY;EAEhB,MAAM,gBAAgB;GACpB,IAAI,UAAU,KAAA,GAAW,qBAAqB,KAAK;GACnD,QAAQ,KAAA;GACR,MAAM,MAAM,UAAU,sBAAsB;GAC5C,MAAM,QAAwB,CAAC;GAC/B,KAAK,MAAM,QAAQ,OAAO;IACxB,MAAM,WAAW,SAAS,IAAI;IAC9B,MAAM,SAAS,UAAU,cAAc,QAAQ,KAAM;IACrD,IAAI,WAAW,MAAM;KACnB,UAAU,MAAM,YAAY,SAAS,SAAS,MAAM;KACpD;IACF;IACA,MAAM,KAAK,MAAM;IACjB,MAAM,WAAW,KAAK,IAAI,IAAI;IAC9B,KAAK,IAAI,MAAM,MAAM;IACrB,MAAM,OAAO,OAAO,sBAAsB;IAE1C,MAAM,IAAI,KAAK,OAAO,IAAI,OAAO,UAAU,aAAa,UAAU;IAClE,MAAM,IAAI,KAAK,MAAM,IAAI,MAAM,UAAU,YAAY,UAAU;IAC/D,UAAU,MAAM,YAAY,SAAS,GAAG,GAAG,EAAE,GAAG;IAChD,UAAU,MAAM,YAAY,SAAS,GAAG,GAAG,EAAE,GAAG;IAChD,UAAU,MAAM,YAAY,SAAS,GAAG,GAAG,KAAK,MAAM,GAAG;IACzD,UAAU,MAAM,YAAY,SAAS,GAAG,GAAG,KAAK,OAAO,GAAG;IAC1D,UAAU,MAAM,YAAY,SAAS,SAAS,OAAO;IACrD,UAAU,MAAM,YACd,SAAS,QACT,aAAa,KAAA,KAAa,aAAa,SAAS,MAAM,GACxD;GACF;GAEA,IAAI,MAAM,WAAW,QAAQ,UAAU,MAAM,MAAM,MAAM,OAAO,SAAS,QAAQ,GAAG,GAAG;IACrF,KAAK,MAAM,QAAQ,SAAS,MAAM,UAAU,IAAI;IAChD,KAAK,MAAM,QAAQ,OAAO,MAAM,QAAQ,IAAI;IAC5C,UAAU;GACZ;GACA,IAAI,WAAW;IAEb,YAAY,UACT,cAAc,EAAE,SAAS,KAAK,CAAC,CAAC,CAChC,MAAK,cAAa,UAAU,cAAc,SAAS;IACtD,IAAI,WAAW,KAAK;GACtB;EACF;EACA,MAAM,aAAa;GACjB,IAAI,UAAU,KAAA,GAAW,QAAQ,sBAAsB,OAAO;EAChE;EACA,MAAM,eAAe;GACnB,YAAY;GACZ,KAAK;EACP;EAIA,MAAM,UAAU,IAAI,iBAAiB,OAAO;EAM5C,MAAM,QAAQ,IAAI,eAAe,OAAO;EACxC,SAAS,MAAM,iBAAiB,eAAe,IAAI;EAGnD,QAAQ,QAAQ,WAAW;GAAE,SAAS;GAAM,WAAW;GAAM,YAAY;EAAK,CAAC;EAC/E,MAAM,QAAQ,SAAS;EACvB,UAAU,iBAAiB,UAAU,MAAM,EAAE,SAAS,KAAK,CAAC;EAC5D,OAAO,iBAAiB,UAAU,IAAI;EAEtC,UAAU,iBAAiB,QAAQ,MAAM,EAAE,SAAS,KAAK,CAAC;EAC1D,UAAU,iBAAiB,iBAAiB,MAAM;EAClD,UAAU,iBAAiB,kBAAkB,MAAM;EACnD,QAAQ;EACR,aAAa;GACX,IAAI,UAAU,KAAA,GAAW,qBAAqB,KAAK;GACnD,QAAQ,WAAW;GACnB,MAAM,WAAW;GACjB,UAAU,oBAAoB,UAAU,IAAI;GAC5C,OAAO,oBAAoB,UAAU,IAAI;GACzC,UAAU,oBAAoB,QAAQ,MAAM,EAAE,SAAS,KAAK,CAAC;GAC7D,SAAS,MAAM,oBAAoB,eAAe,IAAI;GACtD,UAAU,oBAAoB,iBAAiB,MAAM;GACrD,UAAU,oBAAoB,kBAAkB,MAAM;EACxD;CACF,CAAC,IACD,SAAQ,OAAO,KAAK,IAAI,CAC1B,CACF;AACJ,CAAC"}
@@ -0,0 +1,45 @@
1
+ import { Schema } from "effect";
2
+ import * as Mount from "foldkit/mount";
3
+ export declare const MoveStarted: Schema.TaggedStruct<"MoveStarted", {
4
+ readonly pointerId: Schema.Number;
5
+ readonly pointerType: Schema.String;
6
+ }>;
7
+ export type MoveStarted = typeof MoveStarted.Type;
8
+ export declare const Moved: Schema.TaggedStruct<"Moved", {
9
+ readonly pointerId: Schema.Number;
10
+ /** From where the pointer went down, in CSS pixels. */
11
+ readonly deltaX: Schema.Number;
12
+ readonly deltaY: Schema.Number;
13
+ readonly pointerType: Schema.String;
14
+ }>;
15
+ export type Moved = typeof Moved.Type;
16
+ export declare const MoveEnded: Schema.TaggedStruct<"MoveEnded", {
17
+ readonly pointerId: Schema.Number;
18
+ /** `false` when the pointer was cancelled or capture was lost. */
19
+ readonly completed: Schema.Boolean;
20
+ }>;
21
+ export type MoveEnded = typeof MoveEnded.Type;
22
+ export type Fact = MoveStarted | Moved | MoveEnded;
23
+ /**
24
+ * Pointer movement on an element as a Mount: a primary-button pointer down
25
+ * captures the pointer, each move reports the delta from where it started,
26
+ * and up, cancel, or lost capture ends it. Nothing is decided here: a drag
27
+ * threshold, a snap, or a constraint is the parent's `update`. Capture is
28
+ * released with the Mount.
29
+ */
30
+ export declare const Move: Mount.MountDefinitionNoArgs<"Move", {
31
+ readonly _tag: "MoveStarted";
32
+ readonly pointerId: number;
33
+ readonly pointerType: string;
34
+ } | {
35
+ readonly _tag: "Moved";
36
+ readonly pointerId: number;
37
+ readonly deltaX: number;
38
+ readonly deltaY: number;
39
+ readonly pointerType: string;
40
+ } | {
41
+ readonly _tag: "MoveEnded";
42
+ readonly pointerId: number;
43
+ readonly completed: boolean;
44
+ }>;
45
+ //# sourceMappingURL=move.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"move.d.ts","names":[],"sources":["../../src/dom/move.ts"],"mappings":";;qBAGa,aAAW,OAAA;;;;YAIZ,qBAAqB,YAAY;qBAEhC,OAAK,OAAA;;;;;;;YAON,eAAe,MAAM;qBAEpB,WAAS,OAAA;;;;;YAKV,mBAAmB,UAAU;YAE7B,OAAO,cAAc,QAAQ;;;;;;;;qBAsB5B,MAAI,MAAA"}
@@ -0,0 +1,96 @@
1
+ import { Effect, Queue, Schema, Stream } from "effect";
2
+ import * as Mount from "foldkit/mount";
3
+ // src/dom/move.ts
4
+ const MoveStarted = Schema.TaggedStruct("MoveStarted", {
5
+ pointerId: Schema.Number,
6
+ pointerType: Schema.String
7
+ });
8
+ const Moved = Schema.TaggedStruct("Moved", {
9
+ pointerId: Schema.Number,
10
+ /** From where the pointer went down, in CSS pixels. */
11
+ deltaX: Schema.Number,
12
+ deltaY: Schema.Number,
13
+ pointerType: Schema.String
14
+ });
15
+ const MoveEnded = Schema.TaggedStruct("MoveEnded", {
16
+ pointerId: Schema.Number,
17
+ /** `false` when the pointer was cancelled or capture was lost. */
18
+ completed: Schema.Boolean
19
+ });
20
+ /**
21
+ * Pointer movement on an element as a Mount: a primary-button pointer down
22
+ * captures the pointer, each move reports the delta from where it started,
23
+ * and up, cancel, or lost capture ends it. Nothing is decided here: a drag
24
+ * threshold, a snap, or a constraint is the parent's `update`. Capture is
25
+ * released with the Mount.
26
+ */
27
+ const Move = Mount.defineStream("Move", {
28
+ messages: [
29
+ MoveStarted,
30
+ Moved,
31
+ MoveEnded
32
+ ],
33
+ execute: ({ element }) => Stream.callback((queue) => Effect.acquireRelease(Effect.sync(() => {
34
+ const target = element;
35
+ let active = null;
36
+ const offer = (fact) => Queue.offerUnsafe(queue, fact);
37
+ const end = (pointerId, completed) => {
38
+ if (active === null || active.pointerId !== pointerId) return;
39
+ active = null;
40
+ try {
41
+ target.releasePointerCapture?.(pointerId);
42
+ } catch {}
43
+ offer(MoveEnded.make({
44
+ pointerId,
45
+ completed
46
+ }));
47
+ };
48
+ const listeners = [
49
+ ["pointerdown", (event) => {
50
+ const pointer = event;
51
+ if ((pointer.button ?? 0) !== 0 || active !== null) return;
52
+ const pointerId = pointer.pointerId ?? 0;
53
+ active = {
54
+ pointerId,
55
+ x: pointer.clientX ?? 0,
56
+ y: pointer.clientY ?? 0
57
+ };
58
+ try {
59
+ target.setPointerCapture?.(pointerId);
60
+ } catch {}
61
+ offer(MoveStarted.make({
62
+ pointerId,
63
+ pointerType: pointer.pointerType ?? "mouse"
64
+ }));
65
+ }],
66
+ ["pointermove", (event) => {
67
+ const pointer = event;
68
+ const pointerId = pointer.pointerId ?? 0;
69
+ if (active === null || active.pointerId !== pointerId) return;
70
+ offer(Moved.make({
71
+ pointerId,
72
+ deltaX: (pointer.clientX ?? 0) - active.x,
73
+ deltaY: (pointer.clientY ?? 0) - active.y,
74
+ pointerType: pointer.pointerType ?? "mouse"
75
+ }));
76
+ }],
77
+ ["pointerup", (event) => end(event.pointerId ?? 0, true)],
78
+ ["pointercancel", (event) => end(event.pointerId ?? 0, false)],
79
+ ["lostpointercapture", (event) => end(event.pointerId ?? 0, false)]
80
+ ];
81
+ for (const [type, listener] of listeners) element.addEventListener(type, listener);
82
+ return {
83
+ listeners,
84
+ current: () => active
85
+ };
86
+ }), ({ listeners, current }) => Effect.sync(() => {
87
+ for (const [type, listener] of listeners) element.removeEventListener(type, listener);
88
+ const pointer = current();
89
+ if (pointer !== null) try {
90
+ element.releasePointerCapture?.(pointer.pointerId);
91
+ } catch {}
92
+ })))
93
+ });
94
+ export { Move, MoveEnded, MoveStarted, Moved };
95
+
96
+ //# sourceMappingURL=move.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"move.js","names":[],"sources":["../../src/dom/move.ts"],"sourcesContent":["import { Effect, Queue, Schema, Stream } from 'effect'\nimport * as Mount from 'foldkit/mount'\n\nexport const MoveStarted = Schema.TaggedStruct('MoveStarted', {\n pointerId: Schema.Number,\n pointerType: Schema.String,\n})\nexport type MoveStarted = typeof MoveStarted.Type\n\nexport const Moved = Schema.TaggedStruct('Moved', {\n pointerId: Schema.Number,\n /** From where the pointer went down, in CSS pixels. */\n deltaX: Schema.Number,\n deltaY: Schema.Number,\n pointerType: Schema.String,\n})\nexport type Moved = typeof Moved.Type\n\nexport const MoveEnded = Schema.TaggedStruct('MoveEnded', {\n pointerId: Schema.Number,\n /** `false` when the pointer was cancelled or capture was lost. */\n completed: Schema.Boolean,\n})\nexport type MoveEnded = typeof MoveEnded.Type\n\nexport type Fact = MoveStarted | Moved | MoveEnded\n\ntype PointerLike = Event & {\n readonly pointerId?: number\n readonly button?: number\n readonly pointerType?: string\n readonly clientX?: number\n readonly clientY?: number\n}\n\ntype Capturing = Element & {\n setPointerCapture?: (pointerId: number) => void\n releasePointerCapture?: (pointerId: number) => void\n}\n\n/**\n * Pointer movement on an element as a Mount: a primary-button pointer down\n * captures the pointer, each move reports the delta from where it started,\n * and up, cancel, or lost capture ends it. Nothing is decided here: a drag\n * threshold, a snap, or a constraint is the parent's `update`. Capture is\n * released with the Mount.\n */\nexport const Move = Mount.defineStream('Move', {\n messages: [MoveStarted, Moved, MoveEnded],\n execute: ({ element }) =>\n Stream.callback<Fact>(queue =>\n Effect.acquireRelease(\n Effect.sync(() => {\n const target = element as Capturing\n let active: {\n readonly pointerId: number\n readonly x: number\n readonly y: number\n } | null = null\n const offer = (fact: Fact) => Queue.offerUnsafe(queue, fact)\n const end = (pointerId: number, completed: boolean) => {\n if (active === null || active.pointerId !== pointerId) return\n active = null\n try {\n target.releasePointerCapture?.(pointerId)\n } catch {\n // Capture may already be gone; the end is still reported.\n }\n offer(MoveEnded.make({ pointerId, completed }))\n }\n const listeners: ReadonlyArray<readonly [string, (event: Event) => void]> = [\n [\n 'pointerdown',\n event => {\n const pointer = event as PointerLike\n if ((pointer.button ?? 0) !== 0 || active !== null) return\n const pointerId = pointer.pointerId ?? 0\n active = { pointerId, x: pointer.clientX ?? 0, y: pointer.clientY ?? 0 }\n try {\n target.setPointerCapture?.(pointerId)\n } catch {\n // Without capture the move still reports while over the element.\n }\n offer(MoveStarted.make({ pointerId, pointerType: pointer.pointerType ?? 'mouse' }))\n },\n ],\n [\n 'pointermove',\n event => {\n const pointer = event as PointerLike\n const pointerId = pointer.pointerId ?? 0\n if (active === null || active.pointerId !== pointerId) return\n offer(\n Moved.make({\n pointerId,\n deltaX: (pointer.clientX ?? 0) - active.x,\n deltaY: (pointer.clientY ?? 0) - active.y,\n pointerType: pointer.pointerType ?? 'mouse',\n }),\n )\n },\n ],\n ['pointerup', event => end((event as PointerLike).pointerId ?? 0, true)],\n ['pointercancel', event => end((event as PointerLike).pointerId ?? 0, false)],\n ['lostpointercapture', event => end((event as PointerLike).pointerId ?? 0, false)],\n ]\n for (const [type, listener] of listeners) element.addEventListener(type, listener)\n return { listeners, current: () => active }\n }),\n ({ listeners, current }) =>\n Effect.sync(() => {\n for (const [type, listener] of listeners) element.removeEventListener(type, listener)\n const pointer = current()\n if (pointer !== null) {\n try {\n ;(element as Capturing).releasePointerCapture?.(pointer.pointerId)\n } catch {\n // Already released.\n }\n }\n }),\n ),\n ),\n})\n"],"mappings":";;;AAGA,MAAa,cAAc,OAAO,aAAa,eAAe;CAC5D,WAAW,OAAO;CAClB,aAAa,OAAO;AACtB,CAAC;AAGD,MAAa,QAAQ,OAAO,aAAa,SAAS;CAChD,WAAW,OAAO;;CAElB,QAAQ,OAAO;CACf,QAAQ,OAAO;CACf,aAAa,OAAO;AACtB,CAAC;AAGD,MAAa,YAAY,OAAO,aAAa,aAAa;CACxD,WAAW,OAAO;;CAElB,WAAW,OAAO;AACpB,CAAC;;;;;;;;AAyBD,MAAa,OAAO,MAAM,aAAa,QAAQ;CAC7C,UAAU;EAAC;EAAa;EAAO;CAAS;CACxC,UAAU,EAAE,cACV,OAAO,UAAe,UACpB,OAAO,eACL,OAAO,WAAW;EAChB,MAAM,SAAS;EACf,IAAI,SAIO;EACX,MAAM,SAAS,SAAe,MAAM,YAAY,OAAO,IAAI;EAC3D,MAAM,OAAO,WAAmB,cAAuB;GACrD,IAAI,WAAW,QAAQ,OAAO,cAAc,WAAW;GACvD,SAAS;GACT,IAAI;IACF,OAAO,wBAAwB,SAAS;GAC1C,QAAQ,CAER;GACA,MAAM,UAAU,KAAK;IAAE;IAAW;GAAU,CAAC,CAAC;EAChD;EACA,MAAM,YAAsE;GAC1E,CACE,gBACA,UAAS;IACP,MAAM,UAAU;IAChB,KAAK,QAAQ,UAAU,OAAO,KAAK,WAAW,MAAM;IACpD,MAAM,YAAY,QAAQ,aAAa;IACvC,SAAS;KAAE;KAAW,GAAG,QAAQ,WAAW;KAAG,GAAG,QAAQ,WAAW;IAAE;IACvE,IAAI;KACF,OAAO,oBAAoB,SAAS;IACtC,QAAQ,CAER;IACA,MAAM,YAAY,KAAK;KAAE;KAAW,aAAa,QAAQ,eAAe;IAAQ,CAAC,CAAC;GACpF,CACF;GACA,CACE,gBACA,UAAS;IACP,MAAM,UAAU;IAChB,MAAM,YAAY,QAAQ,aAAa;IACvC,IAAI,WAAW,QAAQ,OAAO,cAAc,WAAW;IACvD,MACE,MAAM,KAAK;KACT;KACA,SAAS,QAAQ,WAAW,KAAK,OAAO;KACxC,SAAS,QAAQ,WAAW,KAAK,OAAO;KACxC,aAAa,QAAQ,eAAe;IACtC,CAAC,CACH;GACF,CACF;GACA,CAAC,cAAa,UAAS,IAAK,MAAsB,aAAa,GAAG,IAAI,CAAC;GACvE,CAAC,kBAAiB,UAAS,IAAK,MAAsB,aAAa,GAAG,KAAK,CAAC;GAC5E,CAAC,uBAAsB,UAAS,IAAK,MAAsB,aAAa,GAAG,KAAK,CAAC;EACnF;EACA,KAAK,MAAM,CAAC,MAAM,aAAa,WAAW,QAAQ,iBAAiB,MAAM,QAAQ;EACjF,OAAO;GAAE;GAAW,eAAe;EAAO;CAC5C,CAAC,IACA,EAAE,WAAW,cACZ,OAAO,WAAW;EAChB,KAAK,MAAM,CAAC,MAAM,aAAa,WAAW,QAAQ,oBAAoB,MAAM,QAAQ;EACpF,MAAM,UAAU,QAAQ;EACxB,IAAI,YAAY,MACd,IAAI;GACD,QAAuB,wBAAwB,QAAQ,SAAS;EACnE,QAAQ,CAER;CAEJ,CAAC,CACL,CACF;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { Stream } from "effect";
2
+ import { Url } from "foldkit/url";
3
+ /**
4
+ * The address of the link a reader means to follow, on the page's own
5
+ * origin: for a `Data.preload` before they go (`Site.routing`'s `preload`).
6
+ * A pointer or focus counts once it has rested on a link for 50 ms, and
7
+ * leaving first cancels it, so a pointer sweeping a list reads one page, not
8
+ * every page it crosses. A finger counts at once: the tap that follows is the
9
+ * navigation. Crossing the elements inside a link is staying on it. Without
10
+ * a document the stream is empty.
11
+ */
12
+ export declare const pointedLinks: () => Stream.Stream<Url>;
13
+ //# sourceMappingURL=pointed-links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointed-links.d.ts","names":[],"sources":["../../src/dom/pointed-links.ts"],"mappings":";;;;;;;;;;;qBAiBa,oBAAmB,OAAO,OAAO"}
@@ -0,0 +1,59 @@
1
+ import { Effect, Option, Queue, Stream } from "effect";
2
+ import { fromString } from "foldkit/url";
3
+ // src/dom/pointed-links.ts
4
+ /** How long, in milliseconds, a pointer or focus rests on a link before it counts as intent. */
5
+ const REST = 50;
6
+ const LISTENED = [
7
+ "pointerover",
8
+ "pointerout",
9
+ "focusin",
10
+ "focusout"
11
+ ];
12
+ /**
13
+ * The address of the link a reader means to follow, on the page's own
14
+ * origin: for a `Data.preload` before they go (`Site.routing`'s `preload`).
15
+ * A pointer or focus counts once it has rested on a link for 50 ms, and
16
+ * leaving first cancels it, so a pointer sweeping a list reads one page, not
17
+ * every page it crosses. A finger counts at once: the tap that follows is the
18
+ * navigation. Crossing the elements inside a link is staying on it. Without
19
+ * a document the stream is empty.
20
+ */
21
+ const pointedLinks = () => {
22
+ if (typeof document === "undefined") return Stream.empty;
23
+ const linkOf = (target) => {
24
+ const link = target instanceof Element ? target.closest("a[href]") : null;
25
+ return link instanceof HTMLAnchorElement && link.origin === window.location.origin ? Option.some(link) : Option.none();
26
+ };
27
+ return Stream.callback((queue) => Effect.acquireRelease(Effect.sync(() => {
28
+ let on;
29
+ let waiting;
30
+ const listener = (event) => {
31
+ const found = linkOf(event.target);
32
+ if (Option.isNone(found)) return;
33
+ const link = found.value;
34
+ if (event.type === "pointerout" || event.type === "focusout") {
35
+ const related = "relatedTarget" in event ? event.relatedTarget : null;
36
+ if (related instanceof Node && link.contains(related)) return;
37
+ if (link.href !== on) return;
38
+ on = void 0;
39
+ clearTimeout(waiting);
40
+ return;
41
+ }
42
+ if (link.href === on) return;
43
+ on = link.href;
44
+ clearTimeout(waiting);
45
+ const url = fromString(link.href);
46
+ if (Option.isNone(url)) return;
47
+ if ("pointerType" in event && event.pointerType === "touch") Queue.offerUnsafe(queue, url.value);
48
+ else waiting = setTimeout(() => Queue.offerUnsafe(queue, url.value), REST);
49
+ };
50
+ for (const type of LISTENED) document.addEventListener(type, listener);
51
+ return () => {
52
+ clearTimeout(waiting);
53
+ for (const type of LISTENED) document.removeEventListener(type, listener);
54
+ };
55
+ }), (release) => Effect.sync(release)));
56
+ };
57
+ export { pointedLinks };
58
+
59
+ //# sourceMappingURL=pointed-links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointed-links.js","names":[],"sources":["../../src/dom/pointed-links.ts"],"sourcesContent":["import { Effect, Option, Queue, Stream } from 'effect'\nimport { fromString, type Url } from 'foldkit/url'\n\n/** How long, in milliseconds, a pointer or focus rests on a link before it counts as intent. */\nconst REST = 50\n\nconst LISTENED = ['pointerover', 'pointerout', 'focusin', 'focusout'] as const\n\n/**\n * The address of the link a reader means to follow, on the page's own\n * origin: for a `Data.preload` before they go (`Site.routing`'s `preload`).\n * A pointer or focus counts once it has rested on a link for 50 ms, and\n * leaving first cancels it, so a pointer sweeping a list reads one page, not\n * every page it crosses. A finger counts at once: the tap that follows is the\n * navigation. Crossing the elements inside a link is staying on it. Without\n * a document the stream is empty.\n */\nexport const pointedLinks = (): Stream.Stream<Url> => {\n if (typeof document === 'undefined') return Stream.empty\n const linkOf = (target: EventTarget | null): Option.Option<HTMLAnchorElement> => {\n const link = target instanceof Element ? target.closest('a[href]') : null\n return link instanceof HTMLAnchorElement && link.origin === window.location.origin\n ? Option.some(link)\n : Option.none()\n }\n // One listener for all four events, so they are read in the order they\n // happened: a focus moving between links sends its focusout and focusin in\n // one task, and a merge of four streams could read them the other way round.\n return Stream.callback<Url>(queue =>\n Effect.acquireRelease(\n Effect.sync(() => {\n // The link the reader is on, by its address, and the wait for it to count.\n let on: string | undefined\n let waiting: ReturnType<typeof setTimeout> | undefined\n const listener = (event: Event): void => {\n const found = linkOf(event.target)\n if (Option.isNone(found)) return\n const link = found.value\n if (event.type === 'pointerout' || event.type === 'focusout') {\n const related = 'relatedTarget' in event ? event.relatedTarget : null\n // Leaving for an element inside the same link is staying on it.\n if (related instanceof Node && link.contains(related)) return\n if (link.href !== on) return\n on = undefined\n clearTimeout(waiting)\n return\n }\n if (link.href === on) return\n on = link.href\n clearTimeout(waiting)\n const url = fromString(link.href)\n if (Option.isNone(url)) return\n if ('pointerType' in event && event.pointerType === 'touch')\n Queue.offerUnsafe(queue, url.value)\n else waiting = setTimeout(() => Queue.offerUnsafe(queue, url.value), REST)\n }\n for (const type of LISTENED) document.addEventListener(type, listener)\n return () => {\n clearTimeout(waiting)\n for (const type of LISTENED) document.removeEventListener(type, listener)\n }\n }),\n release => Effect.sync(release),\n ),\n )\n}\n"],"mappings":";;;;AAIA,MAAM,OAAO;AAEb,MAAM,WAAW;CAAC;CAAe;CAAc;CAAW;AAAU;;;;;;;;;;AAWpE,MAAa,qBAAyC;CACpD,IAAI,OAAO,aAAa,aAAa,OAAO,OAAO;CACnD,MAAM,UAAU,WAAiE;EAC/E,MAAM,OAAO,kBAAkB,UAAU,OAAO,QAAQ,SAAS,IAAI;EACrE,OAAO,gBAAgB,qBAAqB,KAAK,WAAW,OAAO,SAAS,SACxE,OAAO,KAAK,IAAI,IAChB,OAAO,KAAK;CAClB;CAIA,OAAO,OAAO,UAAc,UAC1B,OAAO,eACL,OAAO,WAAW;EAEhB,IAAI;EACJ,IAAI;EACJ,MAAM,YAAY,UAAuB;GACvC,MAAM,QAAQ,OAAO,MAAM,MAAM;GACjC,IAAI,OAAO,OAAO,KAAK,GAAG;GAC1B,MAAM,OAAO,MAAM;GACnB,IAAI,MAAM,SAAS,gBAAgB,MAAM,SAAS,YAAY;IAC5D,MAAM,UAAU,mBAAmB,QAAQ,MAAM,gBAAgB;IAEjE,IAAI,mBAAmB,QAAQ,KAAK,SAAS,OAAO,GAAG;IACvD,IAAI,KAAK,SAAS,IAAI;IACtB,KAAK,KAAA;IACL,aAAa,OAAO;IACpB;GACF;GACA,IAAI,KAAK,SAAS,IAAI;GACtB,KAAK,KAAK;GACV,aAAa,OAAO;GACpB,MAAM,MAAM,WAAW,KAAK,IAAI;GAChC,IAAI,OAAO,OAAO,GAAG,GAAG;GACxB,IAAI,iBAAiB,SAAS,MAAM,gBAAgB,SAClD,MAAM,YAAY,OAAO,IAAI,KAAK;QAC/B,UAAU,iBAAiB,MAAM,YAAY,OAAO,IAAI,KAAK,GAAG,IAAI;EAC3E;EACA,KAAK,MAAM,QAAQ,UAAU,SAAS,iBAAiB,MAAM,QAAQ;EACrE,aAAa;GACX,aAAa,OAAO;GACpB,KAAK,MAAM,QAAQ,UAAU,SAAS,oBAAoB,MAAM,QAAQ;EAC1E;CACF,CAAC,IACD,YAAW,OAAO,KAAK,OAAO,CAChC,CACF;AACF"}