foldkit-primitives 0.15.4 → 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-l7InESYh.d.mts → events/input-modality.d.ts} +9 -10
  136. package/dist/events/input-modality.d.ts.map +1 -0
  137. package/dist/{input-modality-XwQOFLip.mjs → events/input-modality.js} +2 -2
  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-C4gHodLc.mjs → internal.js} +7 -5
  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} +10 -306
  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 -335
  373. package/dist/device/index.d.mts.map +0 -1
  374. package/dist/device/index.mjs +0 -493
  375. package/dist/device/index.mjs.map +0 -1
  376. package/dist/dom/index.d.mts +0 -714
  377. package/dist/dom/index.d.mts.map +0 -1
  378. package/dist/dom/index.mjs +0 -1840
  379. package/dist/dom/index.mjs.map +0 -1
  380. package/dist/editable-text-Bg7vil7h.d.mts +0 -307
  381. package/dist/editable-text-Bg7vil7h.d.mts.map +0 -1
  382. package/dist/events/index.d.mts +0 -168
  383. package/dist/events/index.d.mts.map +0 -1
  384. package/dist/events/index.mjs +0 -307
  385. package/dist/events/index.mjs.map +0 -1
  386. package/dist/follow-tab-stop-DM5EI4Ci.mjs +0 -856
  387. package/dist/follow-tab-stop-DM5EI4Ci.mjs.map +0 -1
  388. package/dist/index-Bomdwb7e.d.mts +0 -142
  389. package/dist/index-Bomdwb7e.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-XwQOFLip.mjs.map +0 -1
  393. package/dist/input-modality-l7InESYh.d.mts.map +0 -1
  394. package/dist/interaction/index.d.mts +0 -1193
  395. package/dist/interaction/index.d.mts.map +0 -1
  396. package/dist/interaction/index.mjs +0 -1992
  397. package/dist/interaction/index.mjs.map +0 -1
  398. package/dist/internal-C4gHodLc.mjs.map +0 -1
  399. package/dist/media/index.d.mts +0 -103
  400. package/dist/media/index.d.mts.map +0 -1
  401. package/dist/media/index.mjs +0 -146
  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-BmlJCjn6.mjs +0 -236
  406. package/dist/motion-BmlJCjn6.mjs.map +0 -1
  407. package/dist/net/index.d.mts +0 -338
  408. package/dist/net/index.d.mts.map +0 -1
  409. package/dist/net/index.mjs +0 -530
  410. package/dist/net/index.mjs.map +0 -1
  411. package/dist/observers/index.d.mts +0 -76
  412. package/dist/observers/index.d.mts.map +0 -1
  413. package/dist/observers/index.mjs +0 -155
  414. package/dist/observers/index.mjs.map +0 -1
  415. package/dist/rolldown-runtime-D8jQpDG7.mjs +0 -12
  416. package/dist/state/index.d.mts +0 -432
  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 -167
  420. package/dist/time/index.d.mts.map +0 -1
  421. package/dist/time/index.mjs +0 -236
  422. package/dist/time/index.mjs.map +0 -1
@@ -0,0 +1,131 @@
1
+ import { Effect, Queue, Schema, Stream } from "effect";
2
+ import * as Mount from "foldkit/mount";
3
+ // src/dom/track-box.ts
4
+ /** The attribute on the mounted element naming the element `TrackBox` follows, by id. */
5
+ const TRACK_TARGET_ATTRIBUTE = "data-target";
6
+ /** The custom properties `TrackBox` writes for `name`, as `measured` names `Measure`'s. */
7
+ const trackedBox = (name) => ({
8
+ x: `--fk-${name}-x`,
9
+ y: `--fk-${name}-y`,
10
+ w: `--fk-${name}-w`,
11
+ h: `--fk-${name}-h`,
12
+ radius: `--fk-${name}-radius`
13
+ });
14
+ /** Sent as the followed element changes: its id, and whether it is on the page. */
15
+ const TrackedTarget = Schema.TaggedStruct("TrackedTarget", {
16
+ target: Schema.String,
17
+ found: Schema.Boolean
18
+ });
19
+ /**
20
+ * The radius a box of `width` by `height` draws for a computed
21
+ * `border-top-left-radius` of `value` (`8px`, `50%`, `8px 4px`): its
22
+ * horizontal length in pixels, a share of the width for a percentage, and
23
+ * never more than half the shorter side, where the browser stops it.
24
+ */
25
+ const cornerRadius = (value, width, height) => {
26
+ const first = value.trim().split(/\s+/)[0] ?? "";
27
+ const length = parseFloat(first);
28
+ if (!Number.isFinite(length)) return 0;
29
+ const pixels = first.endsWith("%") ? length * width / 100 : length;
30
+ return Math.max(0, Math.min(pixels, width / 2, height / 2));
31
+ };
32
+ /**
33
+ * Follows another element's box, as a Mount: the element whose id is the
34
+ * mounted element's `data-target` (`TRACK_TARGET_ATTRIBUTE`). Its box in
35
+ * viewport pixels is written on the mounted element as `--fk-<name>-x`,
36
+ * `-y`, `-w` and `-h`, and with `radius`, its top left corner's radius as
37
+ * `--fk-<name>-radius` (`cornerRadius`), so a fixed overlay drawn from them
38
+ * (a tour's cutout, a coach mark's ring) sits over it. While nothing is
39
+ * followed they are removed, so a stylist's fallbacks apply.
40
+ *
41
+ * The box is read again on a scroll anywhere (heard on the way down, since
42
+ * `scroll` does not bubble), a window resize, the followed element's own
43
+ * resize, and any change to the document's elements, which is also how a
44
+ * target drawn anew under the same id is found. `data-target` is read again
45
+ * whenever it changes, so one element can glide from target to target
46
+ * without being drawn again, which a Mount's args, read once, could not do.
47
+ * What moves the target by any other way (a stylesheet added) is seen at the
48
+ * next of these.
49
+ *
50
+ * Whether a target is on the page is the parent's to act on (a tour shows
51
+ * the step in the middle instead), so each change of the target or of
52
+ * whether it is found sends `TrackedTarget`, starting with the first one.
53
+ * Since it sends a Message, a component may draw it by default: a Scene test
54
+ * resolves it with what the parent maps it to. An empty `data-target` follows
55
+ * nothing and sends nothing.
56
+ */
57
+ const TrackBox = Mount.defineStream("TrackBox", {
58
+ messages: [TrackedTarget],
59
+ args: {
60
+ /** The custom properties' prefix: `tour` writes `--fk-tour-x`. */
61
+ name: Schema.String,
62
+ /** Whether to write the target's corner radius too; it reads the target's computed style. */
63
+ radius: Schema.optional(Schema.Boolean)
64
+ },
65
+ execute: ({ element, name, radius = false }) => Stream.callback((queue) => Effect.acquireRelease(Effect.sync(() => {
66
+ const document = element.ownerDocument;
67
+ const view = document.defaultView;
68
+ const properties = trackedBox(name);
69
+ const style = element instanceof HTMLElement ? element.style : void 0;
70
+ let target = null;
71
+ let told;
72
+ const place = () => {
73
+ if (style === void 0) return;
74
+ if (target === null) {
75
+ for (const property of Object.values(properties)) style.removeProperty(property);
76
+ return;
77
+ }
78
+ const box = target.getBoundingClientRect();
79
+ style.setProperty(properties.x, `${box.left}px`);
80
+ style.setProperty(properties.y, `${box.top}px`);
81
+ style.setProperty(properties.w, `${box.width}px`);
82
+ style.setProperty(properties.h, `${box.height}px`);
83
+ if (radius) {
84
+ const corner = getComputedStyle(target).borderTopLeftRadius;
85
+ style.setProperty(properties.radius, `${cornerRadius(corner, box.width, box.height)}px`);
86
+ }
87
+ };
88
+ const follow = () => {
89
+ const id = element.getAttribute("data-target") ?? "";
90
+ const found = id === "" ? null : document.getElementById(id);
91
+ if (found !== target) {
92
+ if (target !== null) resized.unobserve(target);
93
+ if (found !== null) resized.observe(found);
94
+ target = found;
95
+ }
96
+ place();
97
+ if (id !== "" && (told?.target !== id || told.found !== (found !== null))) {
98
+ told = TrackedTarget.make({
99
+ target: id,
100
+ found: found !== null
101
+ });
102
+ Queue.offerUnsafe(queue, told);
103
+ }
104
+ };
105
+ const resized = new ResizeObserver(place);
106
+ const changed = new MutationObserver(follow);
107
+ changed.observe(element, {
108
+ attributes: true,
109
+ attributeFilter: [TRACK_TARGET_ATTRIBUTE]
110
+ });
111
+ changed.observe(document, {
112
+ childList: true,
113
+ subtree: true
114
+ });
115
+ view?.addEventListener("scroll", place, {
116
+ capture: true,
117
+ passive: true
118
+ });
119
+ view?.addEventListener("resize", place);
120
+ follow();
121
+ return () => {
122
+ changed.disconnect();
123
+ resized.disconnect();
124
+ view?.removeEventListener("scroll", place, { capture: true });
125
+ view?.removeEventListener("resize", place);
126
+ };
127
+ }), (stop) => Effect.sync(stop)))
128
+ });
129
+ export { TRACK_TARGET_ATTRIBUTE, TrackBox, TrackedTarget, cornerRadius, trackedBox };
130
+
131
+ //# sourceMappingURL=track-box.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"track-box.js","names":[],"sources":["../../src/dom/track-box.ts"],"sourcesContent":["import { Effect, Queue, Schema, Stream } from 'effect'\nimport * as Mount from 'foldkit/mount'\n\n/** The attribute on the mounted element naming the element `TrackBox` follows, by id. */\nexport const TRACK_TARGET_ATTRIBUTE = 'data-target'\n\n/** The custom properties `TrackBox` writes for `name`, as `measured` names `Measure`'s. */\nexport const trackedBox = (name: string) =>\n ({\n x: `--fk-${name}-x`,\n y: `--fk-${name}-y`,\n w: `--fk-${name}-w`,\n h: `--fk-${name}-h`,\n radius: `--fk-${name}-radius`,\n }) as const\n\n/** Sent as the followed element changes: its id, and whether it is on the page. */\nexport const TrackedTarget = Schema.TaggedStruct('TrackedTarget', {\n target: Schema.String,\n found: Schema.Boolean,\n})\nexport type TrackedTarget = typeof TrackedTarget.Type\n\n/**\n * The radius a box of `width` by `height` draws for a computed\n * `border-top-left-radius` of `value` (`8px`, `50%`, `8px 4px`): its\n * horizontal length in pixels, a share of the width for a percentage, and\n * never more than half the shorter side, where the browser stops it.\n */\nexport const cornerRadius = (value: string, width: number, height: number): number => {\n const first = value.trim().split(/\\s+/)[0] ?? ''\n const length = parseFloat(first)\n if (!Number.isFinite(length)) return 0\n const pixels = first.endsWith('%') ? (length * width) / 100 : length\n return Math.max(0, Math.min(pixels, width / 2, height / 2))\n}\n\n/**\n * Follows another element's box, as a Mount: the element whose id is the\n * mounted element's `data-target` (`TRACK_TARGET_ATTRIBUTE`). Its box in\n * viewport pixels is written on the mounted element as `--fk-<name>-x`,\n * `-y`, `-w` and `-h`, and with `radius`, its top left corner's radius as\n * `--fk-<name>-radius` (`cornerRadius`), so a fixed overlay drawn from them\n * (a tour's cutout, a coach mark's ring) sits over it. While nothing is\n * followed they are removed, so a stylist's fallbacks apply.\n *\n * The box is read again on a scroll anywhere (heard on the way down, since\n * `scroll` does not bubble), a window resize, the followed element's own\n * resize, and any change to the document's elements, which is also how a\n * target drawn anew under the same id is found. `data-target` is read again\n * whenever it changes, so one element can glide from target to target\n * without being drawn again, which a Mount's args, read once, could not do.\n * What moves the target by any other way (a stylesheet added) is seen at the\n * next of these.\n *\n * Whether a target is on the page is the parent's to act on (a tour shows\n * the step in the middle instead), so each change of the target or of\n * whether it is found sends `TrackedTarget`, starting with the first one.\n * Since it sends a Message, a component may draw it by default: a Scene test\n * resolves it with what the parent maps it to. An empty `data-target` follows\n * nothing and sends nothing.\n */\nexport const TrackBox = Mount.defineStream('TrackBox', {\n messages: [TrackedTarget],\n args: {\n /** The custom properties' prefix: `tour` writes `--fk-tour-x`. */\n name: Schema.String,\n /** Whether to write the target's corner radius too; it reads the target's computed style. */\n radius: Schema.optional(Schema.Boolean),\n },\n execute: ({ element, name, radius = false }) =>\n Stream.callback<TrackedTarget>(queue =>\n Effect.acquireRelease(\n Effect.sync(() => {\n const document = element.ownerDocument\n const view = document.defaultView\n const properties = trackedBox(name)\n const style = element instanceof HTMLElement ? element.style : undefined\n let target: Element | null = null\n let told: TrackedTarget | undefined\n\n const place = () => {\n if (style === undefined) return\n if (target === null) {\n for (const property of Object.values(properties)) style.removeProperty(property)\n return\n }\n const box = target.getBoundingClientRect()\n style.setProperty(properties.x, `${box.left}px`)\n style.setProperty(properties.y, `${box.top}px`)\n style.setProperty(properties.w, `${box.width}px`)\n style.setProperty(properties.h, `${box.height}px`)\n if (radius) {\n const corner = getComputedStyle(target).borderTopLeftRadius\n style.setProperty(\n properties.radius,\n `${cornerRadius(corner, box.width, box.height)}px`,\n )\n }\n }\n // Looks the target up again, telling the parent when what it follows, or whether\n // that is found, changed.\n const follow = () => {\n const id = element.getAttribute(TRACK_TARGET_ATTRIBUTE) ?? ''\n const found = id === '' ? null : document.getElementById(id)\n if (found !== target) {\n if (target !== null) resized.unobserve(target)\n if (found !== null) resized.observe(found)\n target = found\n }\n place()\n if (id !== '' && (told?.target !== id || told.found !== (found !== null))) {\n told = TrackedTarget.make({ target: id, found: found !== null })\n Queue.offerUnsafe(queue, told)\n }\n }\n\n // Every observer is made before any observes, so one that throws (jsdom has no\n // ResizeObserver) leaves nothing attached.\n const resized = new ResizeObserver(place)\n const changed = new MutationObserver(follow)\n changed.observe(element, {\n attributes: true,\n attributeFilter: [TRACK_TARGET_ATTRIBUTE],\n })\n changed.observe(document, { childList: true, subtree: true })\n view?.addEventListener('scroll', place, { capture: true, passive: true })\n view?.addEventListener('resize', place)\n follow()\n return () => {\n changed.disconnect()\n resized.disconnect()\n view?.removeEventListener('scroll', place, { capture: true })\n view?.removeEventListener('resize', place)\n }\n }),\n stop => Effect.sync(stop),\n ),\n ),\n})\n"],"mappings":";;;;AAIA,MAAa,yBAAyB;;AAGtC,MAAa,cAAc,UACxB;CACC,GAAG,QAAQ,KAAK;CAChB,GAAG,QAAQ,KAAK;CAChB,GAAG,QAAQ,KAAK;CAChB,GAAG,QAAQ,KAAK;CAChB,QAAQ,QAAQ,KAAK;AACvB;;AAGF,MAAa,gBAAgB,OAAO,aAAa,iBAAiB;CAChE,QAAQ,OAAO;CACf,OAAO,OAAO;AAChB,CAAC;;;;;;;AASD,MAAa,gBAAgB,OAAe,OAAe,WAA2B;CACpF,MAAM,QAAQ,MAAM,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;CAC9C,MAAM,SAAS,WAAW,KAAK;CAC/B,IAAI,CAAC,OAAO,SAAS,MAAM,GAAG,OAAO;CACrC,MAAM,SAAS,MAAM,SAAS,GAAG,IAAK,SAAS,QAAS,MAAM;CAC9D,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,QAAQ,GAAG,SAAS,CAAC,CAAC;AAC5D;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAa,WAAW,MAAM,aAAa,YAAY;CACrD,UAAU,CAAC,aAAa;CACxB,MAAM;;EAEJ,MAAM,OAAO;;EAEb,QAAQ,OAAO,SAAS,OAAO,OAAO;CACxC;CACA,UAAU,EAAE,SAAS,MAAM,SAAS,YAClC,OAAO,UAAwB,UAC7B,OAAO,eACL,OAAO,WAAW;EAChB,MAAM,WAAW,QAAQ;EACzB,MAAM,OAAO,SAAS;EACtB,MAAM,aAAa,WAAW,IAAI;EAClC,MAAM,QAAQ,mBAAmB,cAAc,QAAQ,QAAQ,KAAA;EAC/D,IAAI,SAAyB;EAC7B,IAAI;EAEJ,MAAM,cAAc;GAClB,IAAI,UAAU,KAAA,GAAW;GACzB,IAAI,WAAW,MAAM;IACnB,KAAK,MAAM,YAAY,OAAO,OAAO,UAAU,GAAG,MAAM,eAAe,QAAQ;IAC/E;GACF;GACA,MAAM,MAAM,OAAO,sBAAsB;GACzC,MAAM,YAAY,WAAW,GAAG,GAAG,IAAI,KAAK,GAAG;GAC/C,MAAM,YAAY,WAAW,GAAG,GAAG,IAAI,IAAI,GAAG;GAC9C,MAAM,YAAY,WAAW,GAAG,GAAG,IAAI,MAAM,GAAG;GAChD,MAAM,YAAY,WAAW,GAAG,GAAG,IAAI,OAAO,GAAG;GACjD,IAAI,QAAQ;IACV,MAAM,SAAS,iBAAiB,MAAM,CAAC,CAAC;IACxC,MAAM,YACJ,WAAW,QACX,GAAG,aAAa,QAAQ,IAAI,OAAO,IAAI,MAAM,EAAE,GACjD;GACF;EACF;EAGA,MAAM,eAAe;GACnB,MAAM,KAAK,QAAQ,aAAA,aAAmC,KAAK;GAC3D,MAAM,QAAQ,OAAO,KAAK,OAAO,SAAS,eAAe,EAAE;GAC3D,IAAI,UAAU,QAAQ;IACpB,IAAI,WAAW,MAAM,QAAQ,UAAU,MAAM;IAC7C,IAAI,UAAU,MAAM,QAAQ,QAAQ,KAAK;IACzC,SAAS;GACX;GACA,MAAM;GACN,IAAI,OAAO,OAAO,MAAM,WAAW,MAAM,KAAK,WAAW,UAAU,QAAQ;IACzE,OAAO,cAAc,KAAK;KAAE,QAAQ;KAAI,OAAO,UAAU;IAAK,CAAC;IAC/D,MAAM,YAAY,OAAO,IAAI;GAC/B;EACF;EAIA,MAAM,UAAU,IAAI,eAAe,KAAK;EACxC,MAAM,UAAU,IAAI,iBAAiB,MAAM;EAC3C,QAAQ,QAAQ,SAAS;GACvB,YAAY;GACZ,iBAAiB,CAAC,sBAAsB;EAC1C,CAAC;EACD,QAAQ,QAAQ,UAAU;GAAE,WAAW;GAAM,SAAS;EAAK,CAAC;EAC5D,MAAM,iBAAiB,UAAU,OAAO;GAAE,SAAS;GAAM,SAAS;EAAK,CAAC;EACxE,MAAM,iBAAiB,UAAU,KAAK;EACtC,OAAO;EACP,aAAa;GACX,QAAQ,WAAW;GACnB,QAAQ,WAAW;GACnB,MAAM,oBAAoB,UAAU,OAAO,EAAE,SAAS,KAAK,CAAC;GAC5D,MAAM,oBAAoB,UAAU,KAAK;EAC3C;CACF,CAAC,IACD,SAAQ,OAAO,KAAK,IAAI,CAC1B,CACF;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { Schema, Stream } from "effect";
2
+ export declare const ActiveElementMessage: import("foldkit/message").MessageUnion<{
3
+ readonly Changed: {
4
+ tag: Schema.String;
5
+ id: Schema.NullOr<Schema.String>;
6
+ };
7
+ }>;
8
+ export type ActiveElementMessage = typeof ActiveElementMessage.Type;
9
+ /**
10
+ * Focus changes on the document. Without a document the stream is empty
11
+ * instead of throwing. Lift with `Subscription.persistentEntry`, mapping into
12
+ * the parent's Message.
13
+ */
14
+ export declare const activeElementEvents: () => Stream.Stream<ActiveElementMessage>;
15
+ //# sourceMappingURL=active-element.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-element.d.ts","names":[],"sources":["../../src/events/active-element.ts"],"mappings":";qBASa,gDAAoB;;IACpB,KAAG,OAAA;IAAiB,IAAE,OAAA,OAAA,OAAA;;;YAEvB,8BAA8B,qBAAqB;;;;;;qBAOlD,2BAA0B,OAAO,OAAO"}
@@ -0,0 +1,33 @@
1
+ import { Schema, Stream } from "effect";
2
+ import { defineMessageUnion } from "foldkit/message";
3
+ // src/events/active-element.ts
4
+ /**
5
+ * Focused element as an entry — not a bundle, because elements are not
6
+ * Model facts: this reports the active element's tag and id (both
7
+ * serializable), and the parent stores what matters. Starts with the
8
+ * current answer, then follows `focusin`/`focusout`.
9
+ */
10
+ const ActiveElementMessage = defineMessageUnion({ Changed: {
11
+ tag: Schema.String,
12
+ id: Schema.NullOr(Schema.String)
13
+ } });
14
+ /**
15
+ * Focus changes on the document. Without a document the stream is empty
16
+ * instead of throwing. Lift with `Subscription.persistentEntry`, mapping into
17
+ * the parent's Message.
18
+ */
19
+ const activeElementEvents = () => {
20
+ if (typeof document === "undefined") return Stream.empty;
21
+ const read = () => {
22
+ const element = document.activeElement;
23
+ return ActiveElementMessage.Changed({
24
+ tag: element?.tagName ?? "",
25
+ id: element?.id !== void 0 && element.id !== "" ? element.id : null
26
+ });
27
+ };
28
+ const changes = Stream.mergeAll([Stream.fromEventListener(document, "focusin").pipe(Stream.map(read)), Stream.fromEventListener(document, "focusout").pipe(Stream.map(read))], { concurrency: "unbounded" });
29
+ return Stream.concat(Stream.make(read()), changes);
30
+ };
31
+ export { ActiveElementMessage, activeElementEvents };
32
+
33
+ //# sourceMappingURL=active-element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-element.js","names":[],"sources":["../../src/events/active-element.ts"],"sourcesContent":["/**\n * Focused element as an entry — not a bundle, because elements are not\n * Model facts: this reports the active element's tag and id (both\n * serializable), and the parent stores what matters. Starts with the\n * current answer, then follows `focusin`/`focusout`.\n */\nimport { Schema, Stream } from 'effect'\nimport { defineMessageUnion } from 'foldkit/message'\n\nexport const ActiveElementMessage = defineMessageUnion({\n Changed: { tag: Schema.String, id: Schema.NullOr(Schema.String) },\n})\nexport type ActiveElementMessage = typeof ActiveElementMessage.Type\n\n/**\n * Focus changes on the document. Without a document the stream is empty\n * instead of throwing. Lift with `Subscription.persistentEntry`, mapping into\n * the parent's Message.\n */\nexport const activeElementEvents = (): Stream.Stream<ActiveElementMessage> => {\n if (typeof document === 'undefined') return Stream.empty\n const read = (): ActiveElementMessage => {\n const element = document.activeElement as Element | null | undefined\n return ActiveElementMessage.Changed({\n tag: element?.tagName ?? '',\n id: element?.id !== undefined && element.id !== '' ? element.id : null,\n })\n }\n const changes: Stream.Stream<ActiveElementMessage> = Stream.mergeAll(\n [\n Stream.fromEventListener(document, 'focusin').pipe(Stream.map(read)),\n Stream.fromEventListener(document, 'focusout').pipe(Stream.map(read)),\n ],\n { concurrency: 'unbounded' },\n )\n return Stream.concat(Stream.make(read()), changes)\n}\n"],"mappings":";;;;;;;;;AASA,MAAa,uBAAuB,mBAAmB,EACrD,SAAS;CAAE,KAAK,OAAO;CAAQ,IAAI,OAAO,OAAO,OAAO,MAAM;AAAE,EAClE,CAAC;;;;;;AAQD,MAAa,4BAAiE;CAC5E,IAAI,OAAO,aAAa,aAAa,OAAO,OAAO;CACnD,MAAM,aAAmC;EACvC,MAAM,UAAU,SAAS;EACzB,OAAO,qBAAqB,QAAQ;GAClC,KAAK,SAAS,WAAW;GACzB,IAAI,SAAS,OAAO,KAAA,KAAa,QAAQ,OAAO,KAAK,QAAQ,KAAK;EACpE,CAAC;CACH;CACA,MAAM,UAA+C,OAAO,SAC1D,CACE,OAAO,kBAAkB,UAAU,SAAS,CAAC,CAAC,KAAK,OAAO,IAAI,IAAI,CAAC,GACnE,OAAO,kBAAkB,UAAU,UAAU,CAAC,CAAC,KAAK,OAAO,IAAI,IAAI,CAAC,CACtE,GACA,EAAE,aAAa,YAAY,CAC7B;CACA,OAAO,OAAO,OAAO,OAAO,KAAK,KAAK,CAAC,GAAG,OAAO;AACnD"}
@@ -0,0 +1,22 @@
1
+ export interface KeyPress {
2
+ readonly key: string;
3
+ readonly repeat: boolean;
4
+ readonly ctrl: boolean;
5
+ readonly shift: boolean;
6
+ readonly alt: boolean;
7
+ readonly meta: boolean;
8
+ }
9
+ /**
10
+ * Hotkey matching as a pure function over a `Pressed` payload: `matchHotkey`
11
+ * answers whether a press is the shortcut, so `update` stays a table of
12
+ * chords instead of a nest of modifier checks. Patterns read like
13
+ * `"ctrl+shift+k"`: modifiers first (any order), the key last,
14
+ * case-insensitive, with `cmd`/`command` and `option` as the Mac names for
15
+ * meta and alt. Matching is exact — unlisted modifiers must be up — and
16
+ * auto-repeat never matches, so holding a chord fires once. `space` (or a
17
+ * bare space) means the space key; `esc` means escape. A pattern with
18
+ * no key, or two keys, matches nothing: predicates return false, they do
19
+ * not throw on the hot path.
20
+ */
21
+ export declare const matchHotkey: (pattern: string, press: KeyPress) => boolean;
22
+ //# sourceMappingURL=hotkeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hotkeys.d.ts","names":[],"sources":["../../src/events/hotkeys.ts"],"mappings":"A,iBAAiB;WACN;WACA;WACA;WACA;WACA;WACA;;;;;;;;;;;;;;qBA8CE,cAAW,iBAAmB,OAAS"}
@@ -0,0 +1,56 @@
1
+ // src/events/hotkeys.ts
2
+ const modifierOf = (part) => {
3
+ switch (part) {
4
+ case "ctrl":
5
+ case "control": return "ctrl";
6
+ case "shift": return "shift";
7
+ case "alt":
8
+ case "option": return "alt";
9
+ case "meta":
10
+ case "cmd":
11
+ case "command": return "meta";
12
+ default: return null;
13
+ }
14
+ };
15
+ const keyNameOf = (part) => {
16
+ switch (part) {
17
+ case "spacebar":
18
+ case " ": return "space";
19
+ case "esc": return "escape";
20
+ default: return part;
21
+ }
22
+ };
23
+ /**
24
+ * Hotkey matching as a pure function over a `Pressed` payload: `matchHotkey`
25
+ * answers whether a press is the shortcut, so `update` stays a table of
26
+ * chords instead of a nest of modifier checks. Patterns read like
27
+ * `"ctrl+shift+k"`: modifiers first (any order), the key last,
28
+ * case-insensitive, with `cmd`/`command` and `option` as the Mac names for
29
+ * meta and alt. Matching is exact — unlisted modifiers must be up — and
30
+ * auto-repeat never matches, so holding a chord fires once. `space` (or a
31
+ * bare space) means the space key; `esc` means escape. A pattern with
32
+ * no key, or two keys, matches nothing: predicates return false, they do
33
+ * not throw on the hot path.
34
+ */
35
+ const matchHotkey = (pattern, press) => {
36
+ if (press.repeat) return false;
37
+ const trimmed = pattern.split("+").map((part) => part.trim().toLowerCase()).filter((part) => part !== "");
38
+ const parts = trimmed.length === 0 && pattern.length > 0 ? ["space"] : trimmed;
39
+ const keys = parts.filter((part) => modifierOf(part) === null);
40
+ if (keys.length !== 1) return false;
41
+ if (keyNameOf(keys[0]) !== keyNameOf(press.key.toLowerCase())) return false;
42
+ const required = {
43
+ ctrl: false,
44
+ shift: false,
45
+ alt: false,
46
+ meta: false
47
+ };
48
+ for (const part of parts) {
49
+ const modifier = modifierOf(part);
50
+ if (modifier !== null) required[modifier] = true;
51
+ }
52
+ return required.ctrl === press.ctrl && required.shift === press.shift && required.alt === press.alt && required.meta === press.meta;
53
+ };
54
+ export { matchHotkey };
55
+
56
+ //# sourceMappingURL=hotkeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hotkeys.js","names":[],"sources":["../../src/events/hotkeys.ts"],"sourcesContent":["export interface KeyPress {\n readonly key: string\n readonly repeat: boolean\n readonly ctrl: boolean\n readonly shift: boolean\n readonly alt: boolean\n readonly meta: boolean\n}\n\nconst modifierOf = (part: string): 'ctrl' | 'shift' | 'alt' | 'meta' | null => {\n switch (part) {\n case 'ctrl':\n case 'control':\n return 'ctrl'\n case 'shift':\n return 'shift'\n case 'alt':\n case 'option':\n return 'alt'\n case 'meta':\n case 'cmd':\n case 'command':\n return 'meta'\n default:\n return null\n }\n}\n\nconst keyNameOf = (part: string): string => {\n switch (part) {\n case 'spacebar':\n case ' ':\n return 'space'\n case 'esc':\n return 'escape'\n default:\n return part\n }\n}\n\n/**\n * Hotkey matching as a pure function over a `Pressed` payload: `matchHotkey`\n * answers whether a press is the shortcut, so `update` stays a table of\n * chords instead of a nest of modifier checks. Patterns read like\n * `\"ctrl+shift+k\"`: modifiers first (any order), the key last,\n * case-insensitive, with `cmd`/`command` and `option` as the Mac names for\n * meta and alt. Matching is exact — unlisted modifiers must be up — and\n * auto-repeat never matches, so holding a chord fires once. `space` (or a\n * bare space) means the space key; `esc` means escape. A pattern with\n * no key, or two keys, matches nothing: predicates return false, they do\n * not throw on the hot path.\n */\nexport const matchHotkey = (pattern: string, press: KeyPress): boolean => {\n if (press.repeat) return false\n const trimmed = pattern\n .split('+')\n .map(part => part.trim().toLowerCase())\n .filter(part => part !== '')\n // A bare whitespace pattern means the space key; an empty pattern is malformed.\n const parts = trimmed.length === 0 && pattern.length > 0 ? ['space'] : trimmed\n const keys = parts.filter(part => modifierOf(part) === null)\n if (keys.length !== 1) return false\n if (keyNameOf(keys[0]!) !== keyNameOf(press.key.toLowerCase())) return false\n const required: Record<'ctrl' | 'shift' | 'alt' | 'meta', boolean> = {\n ctrl: false,\n shift: false,\n alt: false,\n meta: false,\n }\n for (const part of parts) {\n const modifier = modifierOf(part)\n if (modifier !== null) required[modifier] = true\n }\n return (\n required.ctrl === press.ctrl &&\n required.shift === press.shift &&\n required.alt === press.alt &&\n required.meta === press.meta\n )\n}\n"],"mappings":";AASA,MAAM,cAAc,SAA2D;CAC7E,QAAQ,MAAR;EACE,KAAK;EACL,KAAK,WACH,OAAO;EACT,KAAK,SACH,OAAO;EACT,KAAK;EACL,KAAK,UACH,OAAO;EACT,KAAK;EACL,KAAK;EACL,KAAK,WACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAEA,MAAM,aAAa,SAAyB;CAC1C,QAAQ,MAAR;EACE,KAAK;EACL,KAAK,KACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,SACE,OAAO;CACX;AACF;;;;;;;;;;;;;AAcA,MAAa,eAAe,SAAiB,UAA6B;CACxE,IAAI,MAAM,QAAQ,OAAO;CACzB,MAAM,UAAU,QACb,MAAM,GAAG,CAAC,CACV,KAAI,SAAQ,KAAK,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CACtC,QAAO,SAAQ,SAAS,EAAE;CAE7B,MAAM,QAAQ,QAAQ,WAAW,KAAK,QAAQ,SAAS,IAAI,CAAC,OAAO,IAAI;CACvE,MAAM,OAAO,MAAM,QAAO,SAAQ,WAAW,IAAI,MAAM,IAAI;CAC3D,IAAI,KAAK,WAAW,GAAG,OAAO;CAC9B,IAAI,UAAU,KAAK,EAAG,MAAM,UAAU,MAAM,IAAI,YAAY,CAAC,GAAG,OAAO;CACvE,MAAM,WAA+D;EACnE,MAAM;EACN,OAAO;EACP,KAAK;EACL,MAAM;CACR;CACA,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAW,WAAW,IAAI;EAChC,IAAI,aAAa,MAAM,SAAS,YAAY;CAC9C;CACA,OACE,SAAS,SAAS,MAAM,QACxB,SAAS,UAAU,MAAM,SACzB,SAAS,QAAQ,MAAM,OACvB,SAAS,SAAS,MAAM;AAE5B"}
@@ -0,0 +1,29 @@
1
+ import { Schema } from "effect";
2
+ import { Bundle } from "foldkit-bundle";
3
+ export declare const IdleModel: Schema.Struct<{
4
+ readonly idle: Schema.Boolean;
5
+ }>;
6
+ export type IdleModel = typeof IdleModel.Type;
7
+ export declare const IdleMessage: import("foldkit/message").MessageUnion<{
8
+ readonly BecameIdle: {};
9
+ readonly BecameActive: {};
10
+ }>;
11
+ export type IdleMessage = typeof IdleMessage.Type;
12
+ /**
13
+ * Idleness as a bundle: `idle` in the Model, flipped by activity and
14
+ * silence. While active, activity debounced past `timeoutMs` settles to
15
+ * `BecameIdle`; while idle, the first activity wakes to `BecameActive` and
16
+ * the dependency flip restarts the watch. Starts active — a lurker idles
17
+ * when the timeout elapses. The clock is Effect's, so tests drive it with
18
+ * TestClock.
19
+ */
20
+ export declare const Idle: Bundle.Bundle<"Idle", {
21
+ readonly timeoutMs: number;
22
+ }, {
23
+ readonly idle: boolean;
24
+ }, {
25
+ readonly _tag: "BecameActive";
26
+ } | {
27
+ readonly _tag: "BecameIdle";
28
+ }, never, never, never, void, {}, {}>;
29
+ //# sourceMappingURL=idle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idle.d.ts","names":[],"sources":["../../src/events/idle.ts"],"mappings":";;qBAMa,WAAS,OAAA;;;YACV,mBAAmB,UAAU;qBAE5B,uCAAW;;;;YACZ,qBAAqB,YAAY;;;;;;;;;qBAsBhC,MAAI,OAAA"}
@@ -0,0 +1,51 @@
1
+ import { Schema, Stream } from "effect";
2
+ import { defineMessageUnion } from "foldkit/message";
3
+ import * as Subscription from "foldkit/subscription";
4
+ import { Bundle } from "foldkit-bundle";
5
+ // src/events/idle.ts
6
+ const IdleModel = Schema.Struct({ idle: Schema.Boolean });
7
+ const IdleMessage = defineMessageUnion({
8
+ BecameIdle: {},
9
+ BecameActive: {}
10
+ });
11
+ const activity = () => {
12
+ if (typeof window === "undefined") return Stream.empty;
13
+ const senses = [
14
+ Stream.fromEventListener(window, "mousemove"),
15
+ Stream.fromEventListener(window, "keydown"),
16
+ Stream.fromEventListener(window, "pointerdown"),
17
+ Stream.fromEventListener(window, "scroll")
18
+ ];
19
+ return Stream.mergeAll(senses, { concurrency: "unbounded" });
20
+ };
21
+ /**
22
+ * Idleness as a bundle: `idle` in the Model, flipped by activity and
23
+ * silence. While active, activity debounced past `timeoutMs` settles to
24
+ * `BecameIdle`; while idle, the first activity wakes to `BecameActive` and
25
+ * the dependency flip restarts the watch. Starts active — a lurker idles
26
+ * when the timeout elapses. The clock is Effect's, so tests drive it with
27
+ * TestClock.
28
+ */
29
+ const Idle = Bundle.make("Idle", {
30
+ Model: IdleModel,
31
+ Message: IdleMessage,
32
+ args: Schema.Struct({ timeoutMs: Schema.Number.pipe(Schema.check(Schema.isGreaterThan(0)), Schema.check(Schema.isFinite())) }),
33
+ init: () => ({ model: { idle: false } }),
34
+ update: (model, message) => IdleMessage.match(message, {
35
+ BecameIdle: () => model.idle ? { model } : { model: {
36
+ ...model,
37
+ idle: true
38
+ } },
39
+ BecameActive: () => model.idle ? { model: {
40
+ ...model,
41
+ idle: false
42
+ } } : { model }
43
+ }),
44
+ subscriptions: ({ timeoutMs }) => Subscription.make()((entry) => ({ watch: entry({ idle: Schema.Boolean }, {
45
+ modelToDependencies: (model) => ({ idle: model.idle }),
46
+ dependenciesToStream: ({ idle }) => idle ? activity().pipe(Stream.take(1), Stream.map(() => IdleMessage.BecameActive())) : Stream.concat(Stream.make(null), activity()).pipe(Stream.debounce(timeoutMs), Stream.map(() => IdleMessage.BecameIdle()))
47
+ }) }))
48
+ });
49
+ export { Idle, IdleMessage, IdleModel };
50
+
51
+ //# sourceMappingURL=idle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idle.js","names":[],"sources":["../../src/events/idle.ts"],"sourcesContent":["import { Schema, Stream } from 'effect'\nimport { defineMessageUnion } from 'foldkit/message'\nimport * as Subscription from 'foldkit/subscription'\nimport type * as Update from 'foldkit/update'\nimport { Bundle } from 'foldkit-bundle'\n\nexport const IdleModel = Schema.Struct({ idle: Schema.Boolean })\nexport type IdleModel = typeof IdleModel.Type\n\nexport const IdleMessage = defineMessageUnion({ BecameIdle: {}, BecameActive: {} })\nexport type IdleMessage = typeof IdleMessage.Type\n\nconst activity = (): Stream.Stream<unknown> => {\n if (typeof window === 'undefined') return Stream.empty\n // One stream per sense; the merge fans into the debounce below.\n const senses: Array<Stream.Stream<unknown>> = [\n Stream.fromEventListener(window, 'mousemove'),\n Stream.fromEventListener(window, 'keydown'),\n Stream.fromEventListener(window, 'pointerdown'),\n Stream.fromEventListener(window, 'scroll'),\n ]\n return Stream.mergeAll(senses, { concurrency: 'unbounded' })\n}\n\n/**\n * Idleness as a bundle: `idle` in the Model, flipped by activity and\n * silence. While active, activity debounced past `timeoutMs` settles to\n * `BecameIdle`; while idle, the first activity wakes to `BecameActive` and\n * the dependency flip restarts the watch. Starts active — a lurker idles\n * when the timeout elapses. The clock is Effect's, so tests drive it with\n * TestClock.\n */\nexport const Idle = Bundle.make('Idle', {\n Model: IdleModel,\n Message: IdleMessage,\n args: Schema.Struct({\n timeoutMs: Schema.Number.pipe(\n Schema.check(Schema.isGreaterThan(0)),\n Schema.check(Schema.isFinite()),\n ),\n }),\n init: () => ({ model: { idle: false } }),\n update: (model, message) =>\n IdleMessage.match<Update.ReturnWithOutMessage<IdleModel, IdleMessage, never>>(message, {\n // One already in flight when the watch restarts can repeat the state.\n BecameIdle: () => (model.idle ? { model } : { model: { ...model, idle: true } }),\n BecameActive: () => (model.idle ? { model: { ...model, idle: false } } : { model }),\n }),\n subscriptions: ({ timeoutMs }): Subscription.Subscriptions<IdleModel, IdleMessage> =>\n Subscription.make<IdleModel, IdleMessage>()(entry => ({\n watch: entry(\n { idle: Schema.Boolean },\n {\n modelToDependencies: model => ({ idle: model.idle }),\n dependenciesToStream: ({ idle }) =>\n idle\n ? activity().pipe(\n Stream.take(1),\n Stream.map(() => IdleMessage.BecameActive()),\n )\n : // Seeded with subscribe time as last-known-alive: silence from\n // here still settles, so a lurker idles without moving first.\n Stream.concat(Stream.make(null), activity()).pipe(\n Stream.debounce(timeoutMs),\n Stream.map(() => IdleMessage.BecameIdle()),\n ),\n },\n ),\n })),\n})\n"],"mappings":";;;;;AAMA,MAAa,YAAY,OAAO,OAAO,EAAE,MAAM,OAAO,QAAQ,CAAC;AAG/D,MAAa,cAAc,mBAAmB;CAAE,YAAY,CAAC;CAAG,cAAc,CAAC;AAAE,CAAC;AAGlF,MAAM,iBAAyC;CAC7C,IAAI,OAAO,WAAW,aAAa,OAAO,OAAO;CAEjD,MAAM,SAAwC;EAC5C,OAAO,kBAAkB,QAAQ,WAAW;EAC5C,OAAO,kBAAkB,QAAQ,SAAS;EAC1C,OAAO,kBAAkB,QAAQ,aAAa;EAC9C,OAAO,kBAAkB,QAAQ,QAAQ;CAC3C;CACA,OAAO,OAAO,SAAS,QAAQ,EAAE,aAAa,YAAY,CAAC;AAC7D;;;;;;;;;AAUA,MAAa,OAAO,OAAO,KAAK,QAAQ;CACtC,OAAO;CACP,SAAS;CACT,MAAM,OAAO,OAAO,EAClB,WAAW,OAAO,OAAO,KACvB,OAAO,MAAM,OAAO,cAAc,CAAC,CAAC,GACpC,OAAO,MAAM,OAAO,SAAS,CAAC,CAChC,EACF,CAAC;CACD,aAAa,EAAE,OAAO,EAAE,MAAM,MAAM,EAAE;CACtC,SAAS,OAAO,YACd,YAAY,MAAkE,SAAS;EAErF,kBAAmB,MAAM,OAAO,EAAE,MAAM,IAAI,EAAE,OAAO;GAAE,GAAG;GAAO,MAAM;EAAK,EAAE;EAC9E,oBAAqB,MAAM,OAAO,EAAE,OAAO;GAAE,GAAG;GAAO,MAAM;EAAM,EAAE,IAAI,EAAE,MAAM;CACnF,CAAC;CACH,gBAAgB,EAAE,gBAChB,aAAa,KAA6B,CAAC,EAAC,WAAU,EACpD,OAAO,MACL,EAAE,MAAM,OAAO,QAAQ,GACvB;EACE,sBAAqB,WAAU,EAAE,MAAM,MAAM,KAAK;EAClD,uBAAuB,EAAE,WACvB,OACI,SAAS,CAAC,CAAC,KACT,OAAO,KAAK,CAAC,GACb,OAAO,UAAU,YAAY,aAAa,CAAC,CAC7C,IAGA,OAAO,OAAO,OAAO,KAAK,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,KAC3C,OAAO,SAAS,SAAS,GACzB,OAAO,UAAU,YAAY,WAAW,CAAC,CAC3C;CACR,CACF,EACF,EAAE;AACN,CAAC"}
@@ -0,0 +1,9 @@
1
+ export * from "./active-element.js";
2
+ export * from "./hotkeys.js";
3
+ export * from "./idle.js";
4
+ export * from "./input-modality.js";
5
+ export * from "./keyboard.js";
6
+ export * from "./pointer.js";
7
+ export * from "./scroll.js";
8
+ export * from "./visibility.js";
9
+ export * from "./window-size.js";
@@ -0,0 +1,10 @@
1
+ export * from "./active-element.js";
2
+ export * from "./hotkeys.js";
3
+ export * from "./idle.js";
4
+ export * from "./input-modality.js";
5
+ export * from "./keyboard.js";
6
+ export * from "./pointer.js";
7
+ export * from "./scroll.js";
8
+ export * from "./visibility.js";
9
+ export * from "./window-size.js";
10
+ export {};
@@ -1,19 +1,19 @@
1
1
  import { Schema } from "effect";
2
2
  import { Bundle } from "foldkit-bundle";
3
- declare const Modality: Schema.Literals<readonly ["keyboard", "pointer", "unknown"]>;
4
- type Modality = typeof Modality.Type;
5
- declare const InputModalityModel: Schema.Struct<{
3
+ export declare const Modality: Schema.Literals<readonly ["keyboard", "pointer", "unknown"]>;
4
+ export type Modality = typeof Modality.Type;
5
+ export declare const InputModalityModel: Schema.Struct<{
6
6
  readonly modality: Schema.Literals<readonly ["keyboard", "pointer", "unknown"]>;
7
7
  }>;
8
- type InputModalityModel = typeof InputModalityModel.Type;
9
- declare const InputModalityMessage: import("foldkit/message").MessageUnion<{
8
+ export type InputModalityModel = typeof InputModalityModel.Type;
9
+ export declare const InputModalityMessage: import("foldkit/message").MessageUnion<{
10
10
  readonly Changed: {
11
11
  modality: Schema.Literals<readonly ["keyboard", "pointer", "unknown"]>;
12
12
  };
13
13
  }>;
14
- type InputModalityMessage = typeof InputModalityMessage.Type;
14
+ export type InputModalityMessage = typeof InputModalityMessage.Type;
15
15
  /** A modifier alone says nothing about how the page is being driven. */
16
- declare const modalityOfKey: (key: string) => Modality | null;
16
+ export declare const modalityOfKey: (key: string) => Modality | null;
17
17
  /**
18
18
  * Input modality as a bundle: whether the user last drove the page by
19
19
  * keyboard or by pointer. The browser reports the facts; the Model keeps the
@@ -21,11 +21,10 @@ declare const modalityOfKey: (key: string) => Modality | null;
21
21
  * reading the DOM, and a replay sees the same answer. CSS `:focus-visible`
22
22
  * is the floor; this is for JavaScript that must know.
23
23
  */
24
- declare const InputModality: Bundle.Bundle<"InputModality", void, {
24
+ export declare const InputModality: Bundle.Bundle<"InputModality", void, {
25
25
  readonly modality: "keyboard" | "pointer" | "unknown";
26
26
  }, {
27
27
  readonly _tag: "Changed";
28
28
  readonly modality: "keyboard" | "pointer" | "unknown";
29
29
  }, never, never, never, void, {}, {}>;
30
- export { modalityOfKey as a, Modality as i, InputModalityMessage as n, InputModalityModel as r, InputModality as t };
31
- //# sourceMappingURL=input-modality-l7InESYh.d.mts.map
30
+ //# sourceMappingURL=input-modality.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-modality.d.ts","names":[],"sources":["../../src/events/input-modality.ts"],"mappings":";;qBAKa,UAAQ,OAAA;YACT,kBAAkB,SAAS;qBAE1B,oBAAkB,OAAA;;;YACnB,4BAA4B,mBAAmB;qBAE9C,gDAAoB;;IAAmC,UAAQ,OAAA;;;YAChE,8BAA8B,qBAAqB;;qBAKlD,gBAAa,gBAAkB;;;;;;;;qBA0B/B,eAAa,OAAA"}
@@ -37,6 +37,6 @@ const InputModality = Bundle.make("InputModality", {
37
37
  update: (model, message) => model.modality === message.modality ? { model } : { model: { modality: message.modality } },
38
38
  subscriptions: () => Subscription.make()(() => ({ changes: Subscription.persistentEntry(modalityStream()) }))
39
39
  });
40
- export { modalityOfKey as a, Modality as i, InputModalityMessage as n, InputModalityModel as r, InputModality as t };
40
+ export { InputModality, InputModalityMessage, InputModalityModel, Modality, modalityOfKey };
41
41
 
42
- //# sourceMappingURL=input-modality-XwQOFLip.mjs.map
42
+ //# sourceMappingURL=input-modality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-modality.js","names":[],"sources":["../../src/events/input-modality.ts"],"sourcesContent":["import { Schema, Stream } from 'effect'\nimport { defineMessageUnion } from 'foldkit/message'\nimport * as Subscription from 'foldkit/subscription'\nimport { Bundle } from 'foldkit-bundle'\n\nexport const Modality = Schema.Literals(['keyboard', 'pointer', 'unknown'])\nexport type Modality = typeof Modality.Type\n\nexport const InputModalityModel = Schema.Struct({ modality: Modality })\nexport type InputModalityModel = typeof InputModalityModel.Type\n\nexport const InputModalityMessage = defineMessageUnion({ Changed: { modality: Modality } })\nexport type InputModalityMessage = typeof InputModalityMessage.Type\n\nconst MODIFIERS = new Set(['Shift', 'Control', 'Alt', 'Meta', 'CapsLock'])\n\n/** A modifier alone says nothing about how the page is being driven. */\nexport const modalityOfKey = (key: string): Modality | null =>\n MODIFIERS.has(key) ? null : 'keyboard'\n\nconst modalityStream = (): Stream.Stream<InputModalityMessage> => {\n if (typeof window === 'undefined') return Stream.empty\n return Stream.mergeAll(\n [\n Stream.fromEventListener<KeyboardEvent>(window, 'keydown', { capture: true }).pipe(\n Stream.filter(event => modalityOfKey(event.key) !== null),\n Stream.map(() => InputModalityMessage.Changed({ modality: 'keyboard' })),\n ),\n Stream.fromEventListener(window, 'pointerdown', { capture: true }).pipe(\n Stream.map(() => InputModalityMessage.Changed({ modality: 'pointer' })),\n ),\n ],\n { concurrency: 'unbounded' },\n )\n}\n\n/**\n * Input modality as a bundle: whether the user last drove the page by\n * keyboard or by pointer. The browser reports the facts; the Model keeps the\n * answer, so a view can show a focus ring only for keyboard users without\n * reading the DOM, and a replay sees the same answer. CSS `:focus-visible`\n * is the floor; this is for JavaScript that must know.\n */\nexport const InputModality = Bundle.make('InputModality', {\n Model: InputModalityModel,\n Message: InputModalityMessage,\n init: () => ({ model: { modality: 'unknown' as const } }),\n update: (model, message) =>\n model.modality === message.modality ? { model } : { model: { modality: message.modality } },\n subscriptions: (): Subscription.Subscriptions<InputModalityModel, InputModalityMessage> =>\n Subscription.make<InputModalityModel, InputModalityMessage>()(() => ({\n changes: Subscription.persistentEntry(modalityStream()),\n })),\n})\n"],"mappings":";;;;;AAKA,MAAa,WAAW,OAAO,SAAS;CAAC;CAAY;CAAW;AAAS,CAAC;AAG1E,MAAa,qBAAqB,OAAO,OAAO,EAAE,UAAU,SAAS,CAAC;AAGtE,MAAa,uBAAuB,mBAAmB,EAAE,SAAS,EAAE,UAAU,SAAS,EAAE,CAAC;AAG1F,MAAM,4BAAY,IAAI,IAAI;CAAC;CAAS;CAAW;CAAO;CAAQ;AAAU,CAAC;;AAGzE,MAAa,iBAAiB,QAC5B,UAAU,IAAI,GAAG,IAAI,OAAO;AAE9B,MAAM,uBAA4D;CAChE,IAAI,OAAO,WAAW,aAAa,OAAO,OAAO;CACjD,OAAO,OAAO,SACZ,CACE,OAAO,kBAAiC,QAAQ,WAAW,EAAE,SAAS,KAAK,CAAC,CAAC,CAAC,KAC5E,OAAO,QAAO,UAAS,cAAc,MAAM,GAAG,MAAM,IAAI,GACxD,OAAO,UAAU,qBAAqB,QAAQ,EAAE,UAAU,WAAW,CAAC,CAAC,CACzE,GACA,OAAO,kBAAkB,QAAQ,eAAe,EAAE,SAAS,KAAK,CAAC,CAAC,CAAC,KACjE,OAAO,UAAU,qBAAqB,QAAQ,EAAE,UAAU,UAAU,CAAC,CAAC,CACxE,CACF,GACA,EAAE,aAAa,YAAY,CAC7B;AACF;;;;;;;;AASA,MAAa,gBAAgB,OAAO,KAAK,iBAAiB;CACxD,OAAO;CACP,SAAS;CACT,aAAa,EAAE,OAAO,EAAE,UAAU,UAAmB,EAAE;CACvD,SAAS,OAAO,YACd,MAAM,aAAa,QAAQ,WAAW,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,UAAU,QAAQ,SAAS,EAAE;CAC5F,qBACE,aAAa,KAA+C,CAAC,QAAQ,EACnE,SAAS,aAAa,gBAAgB,eAAe,CAAC,EACxD,EAAE;AACN,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { Schema, Stream } from "effect";
2
+ import { KeyPress } from "./hotkeys.js";
3
+ export declare const KeyboardMessage: import("foldkit/message").MessageUnion<{
4
+ readonly Pressed: {
5
+ key: Schema.String;
6
+ repeat: Schema.Boolean;
7
+ ctrl: Schema.Boolean;
8
+ shift: Schema.Boolean;
9
+ alt: Schema.Boolean;
10
+ meta: Schema.Boolean;
11
+ };
12
+ readonly Released: {
13
+ key: Schema.String;
14
+ };
15
+ }>;
16
+ export type KeyboardMessage = typeof KeyboardMessage.Type;
17
+ /**
18
+ * Key presses and releases on the window. Without a window the stream is
19
+ * empty instead of throwing. Lift with `Subscription.persistentEntry`, mapping
20
+ * into the parent's Message.
21
+ */
22
+ export declare const keyboardEvents: (options?: {
23
+ /**
24
+ * Whether to cancel a press's default (the page scrolling under an arrow
25
+ * key, the browser's own shortcut), decided in the listener, since a
26
+ * default can only be cancelled before the event finishes dispatching.
27
+ */
28
+ readonly preventDefault?: (press: KeyPress) => boolean;
29
+ }) => Stream.Stream<KeyboardMessage>;
30
+ //# sourceMappingURL=keyboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard.d.ts","names":[],"sources":["../../src/events/keyboard.ts"],"mappings":";;qBAUa,2CAAe;;IAExB,KAAG,OAAA;IACH,QAAM,OAAA;IACN,MAAI,OAAA;IACJ,OAAK,OAAA;IACL,KAAG,OAAA;IACH,MAAI,OAAA;;;IAEM,KAAG,OAAA;;;YAEL,yBAAyB,gBAAgB;;;;;;qBAOxC,iBAAc;;;;;;WAOd,kBAAkB,OAAO;MAEnC,OAAO,OAAO"}
@@ -0,0 +1,55 @@
1
+ import { Effect, Queue, Schema, Stream } from "effect";
2
+ import { defineMessageUnion } from "foldkit/message";
3
+ // src/events/keyboard.ts
4
+ /**
5
+ * Keyboard as an entry — not a bundle, because the parent owns whatever key
6
+ * state it keeps (a held-keys set, a shortcut map, a focused field): this
7
+ * reports presses and releases, including auto-repeat, and the parent
8
+ * stores what matters. Hotkey matching stays application policy.
9
+ */
10
+ const KeyboardMessage = defineMessageUnion({
11
+ Pressed: {
12
+ key: Schema.String,
13
+ repeat: Schema.Boolean,
14
+ ctrl: Schema.Boolean,
15
+ shift: Schema.Boolean,
16
+ alt: Schema.Boolean,
17
+ meta: Schema.Boolean
18
+ },
19
+ Released: { key: Schema.String }
20
+ });
21
+ /**
22
+ * Key presses and releases on the window. Without a window the stream is
23
+ * empty instead of throwing. Lift with `Subscription.persistentEntry`, mapping
24
+ * into the parent's Message.
25
+ */
26
+ const keyboardEvents = (options = {}) => {
27
+ if (typeof window === "undefined") return Stream.empty;
28
+ return Stream.callback((queue) => Effect.acquireRelease(Effect.sync(() => {
29
+ const down = (event) => {
30
+ const press = KeyboardMessage.Pressed({
31
+ key: event.key,
32
+ repeat: event.repeat,
33
+ ctrl: event.ctrlKey,
34
+ shift: event.shiftKey,
35
+ alt: event.altKey,
36
+ meta: event.metaKey
37
+ });
38
+ if (options.preventDefault?.(press) === true) event.preventDefault();
39
+ Queue.offerUnsafe(queue, press);
40
+ };
41
+ const up = (event) => Queue.offerUnsafe(queue, KeyboardMessage.Released({ key: event.key }));
42
+ window.addEventListener("keydown", down);
43
+ window.addEventListener("keyup", up);
44
+ return {
45
+ down,
46
+ up
47
+ };
48
+ }), ({ down, up }) => Effect.sync(() => {
49
+ window.removeEventListener("keydown", down);
50
+ window.removeEventListener("keyup", up);
51
+ })));
52
+ };
53
+ export { KeyboardMessage, keyboardEvents };
54
+
55
+ //# sourceMappingURL=keyboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard.js","names":[],"sources":["../../src/events/keyboard.ts"],"sourcesContent":["/**\n * Keyboard as an entry — not a bundle, because the parent owns whatever key\n * state it keeps (a held-keys set, a shortcut map, a focused field): this\n * reports presses and releases, including auto-repeat, and the parent\n * stores what matters. Hotkey matching stays application policy.\n */\nimport { Effect, Queue, Schema, Stream } from 'effect'\nimport { defineMessageUnion } from 'foldkit/message'\nimport type { KeyPress } from './hotkeys.js'\n\nexport const KeyboardMessage = defineMessageUnion({\n Pressed: {\n key: Schema.String,\n repeat: Schema.Boolean,\n ctrl: Schema.Boolean,\n shift: Schema.Boolean,\n alt: Schema.Boolean,\n meta: Schema.Boolean,\n },\n Released: { key: Schema.String },\n})\nexport type KeyboardMessage = typeof KeyboardMessage.Type\n\n/**\n * Key presses and releases on the window. Without a window the stream is\n * empty instead of throwing. Lift with `Subscription.persistentEntry`, mapping\n * into the parent's Message.\n */\nexport const keyboardEvents = (\n options: {\n /**\n * Whether to cancel a press's default (the page scrolling under an arrow\n * key, the browser's own shortcut), decided in the listener, since a\n * default can only be cancelled before the event finishes dispatching.\n */\n readonly preventDefault?: (press: KeyPress) => boolean\n } = {},\n): Stream.Stream<KeyboardMessage> => {\n if (typeof window === 'undefined') return Stream.empty\n return Stream.callback<KeyboardMessage>(queue =>\n Effect.acquireRelease(\n Effect.sync(() => {\n const down = (event: KeyboardEvent) => {\n const press = KeyboardMessage.Pressed({\n key: event.key,\n repeat: event.repeat,\n ctrl: event.ctrlKey,\n shift: event.shiftKey,\n alt: event.altKey,\n meta: event.metaKey,\n })\n if (options.preventDefault?.(press) === true) event.preventDefault()\n Queue.offerUnsafe(queue, press)\n }\n const up = (event: KeyboardEvent) =>\n Queue.offerUnsafe(queue, KeyboardMessage.Released({ key: event.key }))\n window.addEventListener('keydown', down)\n window.addEventListener('keyup', up)\n return { down, up }\n }),\n ({ down, up }) =>\n Effect.sync(() => {\n window.removeEventListener('keydown', down)\n window.removeEventListener('keyup', up)\n }),\n ),\n )\n}\n"],"mappings":";;;;;;;;;AAUA,MAAa,kBAAkB,mBAAmB;CAChD,SAAS;EACP,KAAK,OAAO;EACZ,QAAQ,OAAO;EACf,MAAM,OAAO;EACb,OAAO,OAAO;EACd,KAAK,OAAO;EACZ,MAAM,OAAO;CACf;CACA,UAAU,EAAE,KAAK,OAAO,OAAO;AACjC,CAAC;;;;;;AAQD,MAAa,kBACX,UAOI,CAAC,MAC8B;CACnC,IAAI,OAAO,WAAW,aAAa,OAAO,OAAO;CACjD,OAAO,OAAO,UAA0B,UACtC,OAAO,eACL,OAAO,WAAW;EAChB,MAAM,QAAQ,UAAyB;GACrC,MAAM,QAAQ,gBAAgB,QAAQ;IACpC,KAAK,MAAM;IACX,QAAQ,MAAM;IACd,MAAM,MAAM;IACZ,OAAO,MAAM;IACb,KAAK,MAAM;IACX,MAAM,MAAM;GACd,CAAC;GACD,IAAI,QAAQ,iBAAiB,KAAK,MAAM,MAAM,MAAM,eAAe;GACnE,MAAM,YAAY,OAAO,KAAK;EAChC;EACA,MAAM,MAAM,UACV,MAAM,YAAY,OAAO,gBAAgB,SAAS,EAAE,KAAK,MAAM,IAAI,CAAC,CAAC;EACvE,OAAO,iBAAiB,WAAW,IAAI;EACvC,OAAO,iBAAiB,SAAS,EAAE;EACnC,OAAO;GAAE;GAAM;EAAG;CACpB,CAAC,IACA,EAAE,MAAM,SACP,OAAO,WAAW;EAChB,OAAO,oBAAoB,WAAW,IAAI;EAC1C,OAAO,oBAAoB,SAAS,EAAE;CACxC,CAAC,CACL,CACF;AACF"}
@@ -0,0 +1,15 @@
1
+ import { Schema, Stream } from "effect";
2
+ export declare const PointerMessage: import("foldkit/message").MessageUnion<{
3
+ readonly Moved: {
4
+ x: Schema.Number;
5
+ y: Schema.Number;
6
+ };
7
+ }>;
8
+ export type PointerMessage = typeof PointerMessage.Type;
9
+ /**
10
+ * Pointer moves on the window. Without a window the stream is empty instead
11
+ * of throwing. Lift with `Subscription.persistentEntry`, mapping into the
12
+ * parent's Message.
13
+ */
14
+ export declare const pointerEvents: () => Stream.Stream<PointerMessage>;
15
+ //# sourceMappingURL=pointer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointer.d.ts","names":[],"sources":["../../src/events/pointer.ts"],"mappings":";qBASa,0CAAc;;IAChB,GAAC,OAAA;IAAiB,GAAC,OAAA;;;YAElB,wBAAwB,eAAe;;;;;;qBAOtC,qBAAoB,OAAO,OAAO"}