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,152 @@
1
+ import { Schema } from "effect";
2
+ import { Bundle, Declared } from "foldkit-bundle";
3
+ import * as Mount from "foldkit/mount";
4
+ import { Behavior } from "foldkit-mixins";
5
+ export declare const PointerType: Schema.Literals<readonly ["mouse", "touch", "pen", "keyboard", "virtual"]>;
6
+ export type PointerType = typeof PointerType.Type;
7
+ export declare const Model: Schema.Struct<{
8
+ /** Down and not yet released or cancelled. For styling. */
9
+ readonly pressed: Schema.Boolean;
10
+ /** The pointer that pressed, so another pointer's up cannot release it. */
11
+ readonly pointerId: Schema.NullOr<Schema.Number>;
12
+ /** Enter or Space is down. */
13
+ readonly key: Schema.NullOr<Schema.String>;
14
+ /** A click arriving before this generation's window ends is the ghost of a pointer press. */
15
+ readonly suppressing: Schema.NullOr<Schema.Number>;
16
+ readonly generation: Schema.Number;
17
+ }>;
18
+ export type Model = typeof Model.Type;
19
+ export declare const Message: import("foldkit/message").MessageUnion<{
20
+ readonly PointerDown: {
21
+ pointerId: Schema.Number;
22
+ button: Schema.Number;
23
+ pointerType: Schema.String;
24
+ };
25
+ readonly PointerUp: {
26
+ pointerId: Schema.Number;
27
+ pointerType: Schema.String;
28
+ shiftKey: Schema.Boolean;
29
+ };
30
+ readonly PointerCancelled: {
31
+ pointerId: Schema.Number;
32
+ };
33
+ readonly KeyDown: {
34
+ key: Schema.String;
35
+ repeat: Schema.Boolean;
36
+ };
37
+ readonly KeyUp: {
38
+ key: Schema.String;
39
+ shiftKey: Schema.Boolean;
40
+ };
41
+ /** `detail` is 0 for a click no pointer made: keyboard on a native control, or assistive technology. */
42
+ readonly Clicked: {
43
+ detail: Schema.Number;
44
+ shiftKey: Schema.Boolean;
45
+ };
46
+ readonly Unsuppressed: {
47
+ generation: Schema.Number;
48
+ };
49
+ }>;
50
+ export type Message = typeof Message.Type;
51
+ export declare const Pressed: Schema.TaggedStruct<"Pressed", {
52
+ readonly pointerType: Schema.Literals<readonly ["mouse", "touch", "pen", "keyboard", "virtual"]>;
53
+ /** Shift was held, for a range selection. */
54
+ readonly shiftKey: Schema.Boolean;
55
+ }>;
56
+ export type Pressed = typeof Pressed.Type;
57
+ export declare const Args: Schema.Struct<{
58
+ /** How long after a pointer press a `click` is taken for its ghost. */
59
+ readonly clickSuppressionMs: Schema.Number;
60
+ }>;
61
+ export type Args = typeof Args.Type;
62
+ export declare const bundle: Bundle.Bundle<"Press", {
63
+ readonly clickSuppressionMs: number;
64
+ }, {
65
+ readonly pressed: boolean;
66
+ readonly pointerId: number | null;
67
+ readonly key: string | null;
68
+ readonly suppressing: number | null;
69
+ readonly generation: number;
70
+ }, {
71
+ readonly _tag: "Clicked";
72
+ readonly detail: number;
73
+ readonly shiftKey: boolean;
74
+ } | {
75
+ readonly _tag: "KeyDown";
76
+ readonly key: string;
77
+ readonly repeat: boolean;
78
+ } | {
79
+ readonly _tag: "KeyUp";
80
+ readonly key: string;
81
+ readonly shiftKey: boolean;
82
+ } | {
83
+ readonly _tag: "PointerCancelled";
84
+ readonly pointerId: number;
85
+ } | {
86
+ readonly _tag: "PointerDown";
87
+ readonly pointerId: number;
88
+ readonly button: number;
89
+ readonly pointerType: string;
90
+ } | {
91
+ readonly _tag: "PointerUp";
92
+ readonly pointerId: number;
93
+ readonly pointerType: string;
94
+ readonly shiftKey: boolean;
95
+ } | {
96
+ readonly _tag: "Unsuppressed";
97
+ readonly generation: number;
98
+ }, {
99
+ readonly _tag: "Pressed";
100
+ readonly pointerType: "keyboard" | "mouse" | "pen" | "touch" | "virtual";
101
+ readonly shiftKey: boolean;
102
+ }, never, never, void, {}, {}>;
103
+ /** What the element reports; `Unsuppressed` comes from the timer, not the DOM. */
104
+ export type Fact = Exclude<Message, {
105
+ readonly _tag: 'Unsuppressed';
106
+ }>;
107
+ /**
108
+ * The element's press-relevant events as facts. Enter and Space key downs
109
+ * are default-prevented so a native control does not also click, and Space
110
+ * does not scroll; the Bundle owns activation. An element marked
111
+ * `aria-disabled="true"` (which the Behavior writes) reports nothing, read
112
+ * at event time so a toggle needs no remount. Nothing else is decided here.
113
+ */
114
+ export declare const events: Mount.MountDefinitionNoArgs<"PressEvents", {
115
+ readonly _tag: "Clicked";
116
+ readonly detail: number;
117
+ readonly shiftKey: boolean;
118
+ } | {
119
+ readonly _tag: "KeyDown";
120
+ readonly key: string;
121
+ readonly repeat: boolean;
122
+ } | {
123
+ readonly _tag: "KeyUp";
124
+ readonly key: string;
125
+ readonly shiftKey: boolean;
126
+ } | {
127
+ readonly _tag: "PointerCancelled";
128
+ readonly pointerId: number;
129
+ } | {
130
+ readonly _tag: "PointerDown";
131
+ readonly pointerId: number;
132
+ readonly button: number;
133
+ readonly pointerType: string;
134
+ } | {
135
+ readonly _tag: "PointerUp";
136
+ readonly pointerId: number;
137
+ readonly pointerType: string;
138
+ readonly shiftKey: boolean;
139
+ }>;
140
+ export interface BehaviorOptions<Input, Slots> {
141
+ readonly target: keyof Slots & string;
142
+ /** Marks the target `aria-disabled`, which also silences its events. */
143
+ readonly disabled?: (input: Input) => boolean;
144
+ }
145
+ /**
146
+ * Attaches the events Mount to the target slot, mapped into the placement's
147
+ * Messages, and writes `data-pressed` while down for styling. The element
148
+ * decides nothing; a click, a touch, Enter, Space, or an assistive
149
+ * technology's click all reach `update` and come out as one `Pressed`.
150
+ */
151
+ export declare const behavior: <Field extends string>(declared: Declared<typeof bundle, Field>) => <Slots>(slots: Slots) => <Input extends { readonly [K in Field]: Model; }, ParentMessage>(options: BehaviorOptions<Input, Slots>) => Behavior.NamedBehavior<Slots, Input, ParentMessage>;
152
+ //# sourceMappingURL=press.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"press.d.ts","names":[],"sources":["../../src/interaction/press.ts"],"mappings":";;;;qBAiBa,aAAW,OAAA;YACZ,qBAAqB,YAAY;qBAEhC,OAAK,OAAA;;;;;;;;;;;YAWN,eAAe,MAAM;qBAEpB,mCAAO;;IACH,WAAS,OAAA;IAAiB,QAAM,OAAA;IAAiB,aAAW,OAAA;;;IAC9D,WAAS,OAAA;IAAiB,aAAW,OAAA;IAAiB,UAAQ,OAAA;;;IACvD,WAAS,OAAA;;;IAClB,KAAG,OAAA;IAAiB,QAAM,OAAA;;;IAC5B,KAAG,OAAA;IAAiB,UAAQ,OAAA;;;;IAE1B,QAAM,OAAA;IAAiB,UAAQ,OAAA;;;IAC1B,YAAU,OAAA;;;YAEhB,iBAAiB,QAAQ;qBAExB,SAAO,OAAA;;;;;YAKR,iBAAiB,QAAQ;qBAExB,MAAI,OAAA;;;;YAOL,cAAc,KAAK;qBAWlB,QAAM,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA4DP,OAAO,QAAQ;WAAoB;;;;;;;;;qBASlC,QAAM,MAAA;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8FF,gBAAgB,OAAO;WAC7B,cAAc;;WAEd,YAAY,OAAO;;;;;;;;qBASjB,WACV,sBAAoB,UAAY,gBAAgB,QAAQ,YACxD,OAAK,OAAS,WACd,0BAA0B,KAAK,QAAQ,UAAS,eAAa,SACnD,gBAAgB,OAAO,WAC/B,SAAS,cAAc,OAAO,OAAO"}
@@ -0,0 +1,229 @@
1
+ import { Effect, Queue, Schema, Stream } from "effect";
2
+ import { defineMessageUnion } from "foldkit/message";
3
+ import { Bundle } from "foldkit-bundle";
4
+ import * as Mount from "foldkit/mount";
5
+ import { Capability } from "foldkit-mixins";
6
+ import { BundleBehavior } from "./bundle-behavior.js";
7
+ // src/interaction/press.ts
8
+ /**
9
+ * Press: pointer and keyboard activation of one element as one fact. A Mount
10
+ * reports what the element saw (pointer down, up, cancel, key down, up,
11
+ * click) with the detail Foldkit's declarative attributes do not carry; the
12
+ * Bundle's `update` decides what counts as a press; the ghost click that
13
+ * follows a touch is suppressed by a timed Command on Effect's clock, never
14
+ * by a clock read in a handler. Activation is an OutMessage, `Pressed`, so
15
+ * the placement must say what a press does.
16
+ */
17
+ const PointerType = Schema.Literals([
18
+ "mouse",
19
+ "touch",
20
+ "pen",
21
+ "keyboard",
22
+ "virtual"
23
+ ]);
24
+ const Model = Schema.Struct({
25
+ /** Down and not yet released or cancelled. For styling. */
26
+ pressed: Schema.Boolean,
27
+ /** The pointer that pressed, so another pointer's up cannot release it. */
28
+ pointerId: Schema.NullOr(Schema.Number),
29
+ /** Enter or Space is down. */
30
+ key: Schema.NullOr(Schema.String),
31
+ /** A click arriving before this generation's window ends is the ghost of a pointer press. */
32
+ suppressing: Schema.NullOr(Schema.Number),
33
+ generation: Schema.Number
34
+ });
35
+ const Message = defineMessageUnion({
36
+ PointerDown: {
37
+ pointerId: Schema.Number,
38
+ button: Schema.Number,
39
+ pointerType: Schema.String
40
+ },
41
+ PointerUp: {
42
+ pointerId: Schema.Number,
43
+ pointerType: Schema.String,
44
+ shiftKey: Schema.Boolean
45
+ },
46
+ PointerCancelled: { pointerId: Schema.Number },
47
+ KeyDown: {
48
+ key: Schema.String,
49
+ repeat: Schema.Boolean
50
+ },
51
+ KeyUp: {
52
+ key: Schema.String,
53
+ shiftKey: Schema.Boolean
54
+ },
55
+ /** `detail` is 0 for a click no pointer made: keyboard on a native control, or assistive technology. */
56
+ Clicked: {
57
+ detail: Schema.Number,
58
+ shiftKey: Schema.Boolean
59
+ },
60
+ Unsuppressed: { generation: Schema.Number }
61
+ });
62
+ const Pressed = Schema.TaggedStruct("Pressed", {
63
+ pointerType: PointerType,
64
+ /** Shift was held, for a range selection. */
65
+ shiftKey: Schema.Boolean
66
+ });
67
+ const Args = Schema.Struct({
68
+ /** How long after a pointer press a `click` is taken for its ghost. */
69
+ clickSuppressionMs: Schema.Number.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0)), Schema.check(Schema.isFinite())) });
70
+ const idle = (model) => ({
71
+ ...model,
72
+ pressed: false,
73
+ pointerId: null,
74
+ key: null
75
+ });
76
+ const isActivationKey = (key) => key === "Enter" || key === " ";
77
+ const asPointerType = (raw) => raw === "touch" || raw === "pen" ? raw : "mouse";
78
+ const bundle = Bundle.make("Press", {
79
+ Model,
80
+ Message,
81
+ args: Args,
82
+ init: () => ({ model: {
83
+ pressed: false,
84
+ pointerId: null,
85
+ key: null,
86
+ suppressing: null,
87
+ generation: 0
88
+ } }),
89
+ update: (model, message, args) => Message.match(message, {
90
+ PointerDown: ({ pointerId, button }) => button !== 0 || model.pointerId !== null ? { model } : { model: {
91
+ ...model,
92
+ pressed: true,
93
+ pointerId
94
+ } },
95
+ PointerUp: ({ pointerId, pointerType, shiftKey }) => {
96
+ if (model.pointerId !== pointerId) return { model };
97
+ const generation = model.generation + 1;
98
+ return {
99
+ model: {
100
+ ...idle(model),
101
+ suppressing: generation,
102
+ generation
103
+ },
104
+ commands: [{
105
+ name: "Press.unsuppress",
106
+ args: { generation },
107
+ effect: Effect.as(Effect.sleep(args.clickSuppressionMs), Message.Unsuppressed({ generation }))
108
+ }],
109
+ outMessage: Pressed.make({
110
+ pointerType: asPointerType(pointerType),
111
+ shiftKey
112
+ })
113
+ };
114
+ },
115
+ PointerCancelled: ({ pointerId }) => model.pointerId === pointerId ? { model: idle(model) } : { model },
116
+ KeyDown: ({ key, repeat }) => !isActivationKey(key) || repeat || model.key !== null || model.pointerId !== null ? { model } : { model: {
117
+ ...model,
118
+ pressed: true,
119
+ key
120
+ } },
121
+ KeyUp: ({ key, shiftKey }) => model.key === key ? {
122
+ model: idle(model),
123
+ outMessage: Pressed.make({
124
+ pointerType: "keyboard",
125
+ shiftKey
126
+ })
127
+ } : { model },
128
+ Clicked: ({ detail, shiftKey }) => detail === 0 ? {
129
+ model,
130
+ outMessage: Pressed.make({
131
+ pointerType: "virtual",
132
+ shiftKey
133
+ })
134
+ } : model.suppressing !== null ? { model } : {
135
+ model,
136
+ outMessage: Pressed.make({
137
+ pointerType: "mouse",
138
+ shiftKey
139
+ })
140
+ },
141
+ Unsuppressed: ({ generation }) => model.suppressing === generation ? { model: {
142
+ ...model,
143
+ suppressing: null
144
+ } } : { model }
145
+ })
146
+ });
147
+ /**
148
+ * The element's press-relevant events as facts. Enter and Space key downs
149
+ * are default-prevented so a native control does not also click, and Space
150
+ * does not scroll; the Bundle owns activation. An element marked
151
+ * `aria-disabled="true"` (which the Behavior writes) reports nothing, read
152
+ * at event time so a toggle needs no remount. Nothing else is decided here.
153
+ */
154
+ const events = Mount.defineStream("PressEvents", {
155
+ messages: [
156
+ Message.PointerDown,
157
+ Message.PointerUp,
158
+ Message.PointerCancelled,
159
+ Message.KeyDown,
160
+ Message.KeyUp,
161
+ Message.Clicked
162
+ ],
163
+ execute: ({ element }) => Stream.callback((queue) => Effect.acquireRelease(Effect.sync(() => {
164
+ const offer = (message) => {
165
+ if (element.getAttribute("aria-disabled") === "true") return;
166
+ Queue.offerUnsafe(queue, message);
167
+ };
168
+ const listeners = [
169
+ ["pointerdown", (event) => {
170
+ const pointer = event;
171
+ offer(Message.PointerDown({
172
+ pointerId: pointer.pointerId ?? 0,
173
+ button: pointer.button ?? 0,
174
+ pointerType: pointer.pointerType ?? "mouse"
175
+ }));
176
+ }],
177
+ ["pointerup", (event) => {
178
+ const pointer = event;
179
+ offer(Message.PointerUp({
180
+ pointerId: pointer.pointerId ?? 0,
181
+ pointerType: pointer.pointerType ?? "mouse",
182
+ shiftKey: pointer.shiftKey ?? false
183
+ }));
184
+ }],
185
+ ["pointerleave", (event) => offer(Message.PointerCancelled({ pointerId: event.pointerId ?? 0 }))],
186
+ ["pointercancel", (event) => offer(Message.PointerCancelled({ pointerId: event.pointerId ?? 0 }))],
187
+ ["keydown", (event) => {
188
+ const key = event;
189
+ if (isActivationKey(key.key)) key.preventDefault();
190
+ offer(Message.KeyDown({
191
+ key: key.key,
192
+ repeat: key.repeat
193
+ }));
194
+ }],
195
+ ["keyup", (event) => {
196
+ const key = event;
197
+ offer(Message.KeyUp({
198
+ key: key.key,
199
+ shiftKey: key.shiftKey
200
+ }));
201
+ }],
202
+ ["click", (event) => {
203
+ const click = event;
204
+ offer(Message.Clicked({
205
+ detail: click.detail ?? 0,
206
+ shiftKey: click.shiftKey ?? false
207
+ }));
208
+ }]
209
+ ];
210
+ for (const [type, listener] of listeners) element.addEventListener(type, listener);
211
+ return listeners;
212
+ }), (listeners) => Effect.sync(() => {
213
+ for (const [type, listener] of listeners) element.removeEventListener(type, listener);
214
+ })))
215
+ });
216
+ /**
217
+ * Attaches the events Mount to the target slot, mapped into the placement's
218
+ * Messages, and writes `data-pressed` while down for styling. The element
219
+ * decides nothing; a click, a touch, Enter, Space, or an assistive
220
+ * technology's click all reach `update` and come out as one `Pressed`.
221
+ */
222
+ const behavior = (declared) => (slots) => (options) => BundleBehavior.fromBundle(declared)(slots)({ [options.target]: {
223
+ requires: { capability: Capability.Interactive },
224
+ attributes: ({ input, h }) => [...input[declared.field].pressed ? [h.DataAttribute("pressed", "true")] : [], ...options.disabled?.(input) === true ? [h.AriaDisabled(true)] : []],
225
+ events: events()
226
+ } }, { name: "Press" });
227
+ export { Args, Message, Model, PointerType, Pressed, behavior, bundle, events };
228
+
229
+ //# sourceMappingURL=press.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"press.js","names":[],"sources":["../../src/interaction/press.ts"],"sourcesContent":["/**\n * Press: pointer and keyboard activation of one element as one fact. A Mount\n * reports what the element saw (pointer down, up, cancel, key down, up,\n * click) with the detail Foldkit's declarative attributes do not carry; the\n * Bundle's `update` decides what counts as a press; the ghost click that\n * follows a touch is suppressed by a timed Command on Effect's clock, never\n * by a clock read in a handler. Activation is an OutMessage, `Pressed`, so\n * the placement must say what a press does.\n */\nimport { Effect, Queue, Schema, Stream } from 'effect'\nimport { defineMessageUnion } from 'foldkit/message'\nimport * as Mount from 'foldkit/mount'\nimport type * as Update from 'foldkit/update'\nimport { Bundle, type Declared } from 'foldkit-bundle'\nimport { Behavior, Capability } from 'foldkit-mixins'\nimport { BundleBehavior } from './bundle-behavior.js'\n\nexport const PointerType = Schema.Literals(['mouse', 'touch', 'pen', 'keyboard', 'virtual'])\nexport type PointerType = typeof PointerType.Type\n\nexport const Model = Schema.Struct({\n /** Down and not yet released or cancelled. For styling. */\n pressed: Schema.Boolean,\n /** The pointer that pressed, so another pointer's up cannot release it. */\n pointerId: Schema.NullOr(Schema.Number),\n /** Enter or Space is down. */\n key: Schema.NullOr(Schema.String),\n /** A click arriving before this generation's window ends is the ghost of a pointer press. */\n suppressing: Schema.NullOr(Schema.Number),\n generation: Schema.Number,\n})\nexport type Model = typeof Model.Type\n\nexport const Message = defineMessageUnion({\n PointerDown: { pointerId: Schema.Number, button: Schema.Number, pointerType: Schema.String },\n PointerUp: { pointerId: Schema.Number, pointerType: Schema.String, shiftKey: Schema.Boolean },\n PointerCancelled: { pointerId: Schema.Number },\n KeyDown: { key: Schema.String, repeat: Schema.Boolean },\n KeyUp: { key: Schema.String, shiftKey: Schema.Boolean },\n /** `detail` is 0 for a click no pointer made: keyboard on a native control, or assistive technology. */\n Clicked: { detail: Schema.Number, shiftKey: Schema.Boolean },\n Unsuppressed: { generation: Schema.Number },\n})\nexport type Message = typeof Message.Type\n\nexport const Pressed = Schema.TaggedStruct('Pressed', {\n pointerType: PointerType,\n /** Shift was held, for a range selection. */\n shiftKey: Schema.Boolean,\n})\nexport type Pressed = typeof Pressed.Type\n\nexport const Args = Schema.Struct({\n /** How long after a pointer press a `click` is taken for its ghost. */\n clickSuppressionMs: Schema.Number.pipe(\n Schema.check(Schema.isGreaterThanOrEqualTo(0)),\n Schema.check(Schema.isFinite()),\n ),\n})\nexport type Args = typeof Args.Type\n\nconst idle = (model: Model): Model => ({ ...model, pressed: false, pointerId: null, key: null })\n\nconst isActivationKey = (key: string): boolean => key === 'Enter' || key === ' '\n\nconst asPointerType = (raw: string): PointerType =>\n raw === 'touch' || raw === 'pen' ? raw : 'mouse'\n\ntype Return = Update.ReturnWithOutMessage<Model, Message, Pressed>\n\nexport const bundle = Bundle.make('Press', {\n Model,\n Message,\n args: Args,\n init: () => ({\n model: { pressed: false, pointerId: null, key: null, suppressing: null, generation: 0 },\n }),\n update: (model, message, args): Return =>\n Message.match<Return>(message, {\n PointerDown: ({ pointerId, button }) =>\n button !== 0 || model.pointerId !== null\n ? { model }\n : { model: { ...model, pressed: true, pointerId } },\n PointerUp: ({ pointerId, pointerType, shiftKey }) => {\n if (model.pointerId !== pointerId) return { model }\n const generation = model.generation + 1\n return {\n model: { ...idle(model), suppressing: generation, generation },\n commands: [\n {\n name: 'Press.unsuppress',\n args: { generation },\n effect: Effect.as(\n Effect.sleep(args.clickSuppressionMs),\n Message.Unsuppressed({ generation }),\n ),\n },\n ],\n outMessage: Pressed.make({ pointerType: asPointerType(pointerType), shiftKey }),\n }\n },\n PointerCancelled: ({ pointerId }) =>\n model.pointerId === pointerId ? { model: idle(model) } : { model },\n KeyDown: ({ key, repeat }) =>\n !isActivationKey(key) || repeat || model.key !== null || model.pointerId !== null\n ? { model }\n : { model: { ...model, pressed: true, key } },\n KeyUp: ({ key, shiftKey }) =>\n model.key === key\n ? { model: idle(model), outMessage: Pressed.make({ pointerType: 'keyboard', shiftKey }) }\n : { model },\n Clicked: ({ detail, shiftKey }) =>\n detail === 0\n ? { model, outMessage: Pressed.make({ pointerType: 'virtual', shiftKey }) }\n : model.suppressing !== null\n ? { model }\n : { model, outMessage: Pressed.make({ pointerType: 'mouse', shiftKey }) },\n Unsuppressed: ({ generation }) =>\n model.suppressing === generation ? { model: { ...model, suppressing: null } } : { model },\n }),\n})\n\ntype PointerLike = Event & {\n readonly pointerId?: number\n readonly button?: number\n readonly pointerType?: string\n readonly shiftKey?: boolean\n}\n\n/** What the element reports; `Unsuppressed` comes from the timer, not the DOM. */\nexport type Fact = Exclude<Message, { readonly _tag: 'Unsuppressed' }>\n\n/**\n * The element's press-relevant events as facts. Enter and Space key downs\n * are default-prevented so a native control does not also click, and Space\n * does not scroll; the Bundle owns activation. An element marked\n * `aria-disabled=\"true\"` (which the Behavior writes) reports nothing, read\n * at event time so a toggle needs no remount. Nothing else is decided here.\n */\nexport const events = Mount.defineStream('PressEvents', {\n messages: [\n Message.PointerDown,\n Message.PointerUp,\n Message.PointerCancelled,\n Message.KeyDown,\n Message.KeyUp,\n Message.Clicked,\n ],\n execute: ({ element }) =>\n Stream.callback<Fact>(queue =>\n Effect.acquireRelease(\n Effect.sync(() => {\n const offer = (message: Fact) => {\n if (element.getAttribute('aria-disabled') === 'true') return\n Queue.offerUnsafe(queue, message)\n }\n const listeners: ReadonlyArray<readonly [string, (event: Event) => void]> = [\n [\n 'pointerdown',\n event => {\n const pointer = event as PointerLike\n offer(\n Message.PointerDown({\n pointerId: pointer.pointerId ?? 0,\n button: pointer.button ?? 0,\n pointerType: pointer.pointerType ?? 'mouse',\n }),\n )\n },\n ],\n [\n 'pointerup',\n event => {\n const pointer = event as PointerLike\n offer(\n Message.PointerUp({\n pointerId: pointer.pointerId ?? 0,\n pointerType: pointer.pointerType ?? 'mouse',\n shiftKey: pointer.shiftKey ?? false,\n }),\n )\n },\n ],\n [\n 'pointerleave',\n event =>\n offer(\n Message.PointerCancelled({ pointerId: (event as PointerLike).pointerId ?? 0 }),\n ),\n ],\n [\n 'pointercancel',\n event =>\n offer(\n Message.PointerCancelled({ pointerId: (event as PointerLike).pointerId ?? 0 }),\n ),\n ],\n [\n 'keydown',\n event => {\n const key = event as KeyboardEvent\n if (isActivationKey(key.key)) key.preventDefault()\n offer(Message.KeyDown({ key: key.key, repeat: key.repeat }))\n },\n ],\n [\n 'keyup',\n event => {\n const key = event as KeyboardEvent\n offer(Message.KeyUp({ key: key.key, shiftKey: key.shiftKey }))\n },\n ],\n [\n 'click',\n event => {\n const click = event as MouseEvent\n offer(\n Message.Clicked({ detail: click.detail ?? 0, shiftKey: click.shiftKey ?? false }),\n )\n },\n ],\n ]\n for (const [type, listener] of listeners) element.addEventListener(type, listener)\n return listeners\n }),\n listeners =>\n Effect.sync(() => {\n for (const [type, listener] of listeners) element.removeEventListener(type, listener)\n }),\n ),\n ),\n})\n\nexport interface BehaviorOptions<Input, Slots> {\n readonly target: keyof Slots & string\n /** Marks the target `aria-disabled`, which also silences its events. */\n readonly disabled?: (input: Input) => boolean\n}\n\n/**\n * Attaches the events Mount to the target slot, mapped into the placement's\n * Messages, and writes `data-pressed` while down for styling. The element\n * decides nothing; a click, a touch, Enter, Space, or an assistive\n * technology's click all reach `update` and come out as one `Pressed`.\n */\nexport const behavior =\n <Field extends string>(declared: Declared<typeof bundle, Field>) =>\n <Slots>(slots: Slots) =>\n <Input extends { readonly [K in Field]: Model }, ParentMessage>(\n options: BehaviorOptions<Input, Slots>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n BundleBehavior.fromBundle(declared)(slots)<Input, ParentMessage>(\n {\n [options.target]: {\n requires: { capability: Capability.Interactive },\n attributes: ({ input, h }) => [\n ...(input[declared.field].pressed ? [h.DataAttribute('pressed', 'true')] : []),\n ...(options.disabled?.(input) === true ? [h.AriaDisabled(true)] : []),\n ],\n events: events(),\n },\n },\n { name: 'Press' },\n )\n"],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import { Schema } from "effect";
2
+ import { Bundle, Declared } from "foldkit-bundle";
3
+ import { Behavior, Behaviors, SlotItem } from "foldkit-mixins";
4
+ import { Attribute, HtmlBuilder, KeyboardModifiers } from "foldkit/html";
5
+ export declare const Orientation: Schema.Literals<readonly ["vertical", "horizontal", "both"]>;
6
+ export type Orientation = typeof Orientation.Type;
7
+ export declare const Model: Schema.Struct<{
8
+ /** The current item's id, or `null` before any item has been focused. */
9
+ readonly current: Schema.NullOr<Schema.String>;
10
+ }>;
11
+ export type Model = typeof Model.Type;
12
+ export declare const Message: import("foldkit/message").MessageUnion<{
13
+ /** An item became current: the user focused it, or a key moved there. */
14
+ readonly Focused: {
15
+ id: Schema.String;
16
+ };
17
+ }>;
18
+ export type Message = typeof Message.Type;
19
+ export declare const Args: Schema.Struct<{
20
+ readonly orientation: Schema.Literals<readonly ["vertical", "horizontal", "both"]>;
21
+ /** Wrap from the last enabled item to the first, and back. */
22
+ readonly loop: Schema.Boolean;
23
+ /** Keep DOM focus on the container and point at the current item with
24
+ * `aria-activedescendant` instead of moving focus. */
25
+ readonly virtual: Schema.Boolean;
26
+ }>;
27
+ export type Args = typeof Args.Type;
28
+ export declare const bundle: Bundle.Bundle<"RovingTabindex", {
29
+ readonly orientation: "both" | "horizontal" | "vertical";
30
+ readonly loop: boolean;
31
+ readonly virtual: boolean;
32
+ }, {
33
+ readonly current: string | null;
34
+ }, {
35
+ readonly _tag: "Focused";
36
+ readonly id: string;
37
+ }, never, never, never, void, {}, {}>;
38
+ export type Direction = 'ltr' | 'rtl';
39
+ export interface MoveOptions {
40
+ readonly orientation: Orientation;
41
+ readonly loop: boolean;
42
+ readonly direction: Direction;
43
+ /** How many enabled items PageUp and PageDown move; absent, they are not handled. */
44
+ readonly page?: number;
45
+ }
46
+ /**
47
+ * The index the key moves to from `current`, over the enabled indices only, or
48
+ * `undefined` when the key is not a navigation key here. `current` may be
49
+ * `-1` (nothing current yet): arrows then land on the first or last enabled
50
+ * item. Under `rtl`, left and right swap. PageUp and PageDown move by `page`
51
+ * and clamp at the ends, never wrapping.
52
+ */
53
+ export declare const move: (enabled: ReadonlyArray<number>, current: number, key: string, modifiers: KeyboardModifiers, options: MoveOptions) => number | undefined;
54
+ /** The item that holds the tab stop: the current one, else the first enabled. */
55
+ export declare const tabStop: (items: Behaviors.Collection.Items<unknown>, current: string | null) => number;
56
+ export interface BehaviorOptions<Input, Slots> {
57
+ /** The slot that receives the arrow keys. */
58
+ readonly container: keyof Slots & string;
59
+ /** The slot rendered once per item; must carry the item's id (see `Behaviors.Collection`). */
60
+ readonly item: keyof Slots & string;
61
+ readonly items: (input: Input) => Behaviors.Collection.Items<unknown>;
62
+ /** Default `'ltr'`; return `'rtl'` to swap left and right. */
63
+ readonly direction?: (input: Input) => Direction;
64
+ }
65
+ /** A selector for an element by id, safe for any id. */
66
+ export declare const idSelector: (id: string) => string;
67
+ /**
68
+ * The attributes one item gets: `tabindex` 0 when it holds the tab stop and
69
+ * -1 otherwise (none under `virtual`), and `OnFocus` reporting it current.
70
+ * Shared with `ListNavigation`.
71
+ */
72
+ export declare const itemAttributes: <ParentMessage>(h: HtmlBuilder<ParentMessage>, items: Behaviors.Collection.Items<unknown>, current: string | null, item: SlotItem, virtual: boolean, focused: (id: string) => ParentMessage) => ReadonlyArray<Attribute<ParentMessage>>;
73
+ /**
74
+ * Wires a placed `RovingTabindex` to the slots: the container's arrow, Home
75
+ * and End keys focus the next item (synchronously, then dispatch), each item
76
+ * gets `tabindex` 0 or -1 and reports `Focused` when focused. Under `virtual`
77
+ * DOM focus never leaves the container: the key only dispatches, the
78
+ * container carries `aria-activedescendant`, and items keep no `tabindex`.
79
+ *
80
+ * Every handled key is default-prevented. Nothing is written on dispose: the
81
+ * attributes are data, so a view that no longer attaches this leaves no
82
+ * `tabindex` behind.
83
+ */
84
+ export declare const behavior: <Field extends string>(declared: Declared<typeof bundle, Field>, args: Args) => <Slots>(slots: Slots) => <Input extends { readonly [K in Field]: Model; }, ParentMessage>(options: BehaviorOptions<Input, Slots>) => Behavior.NamedBehavior<Slots, Input, ParentMessage>;
85
+ //# sourceMappingURL=roving-tabindex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roving-tabindex.d.ts","names":[],"sources":["../../src/interaction/roving-tabindex.ts"],"mappings":";;;;qBAea,aAAW,OAAA;YACZ,qBAAqB,YAAY;qBAEhC,OAAK,OAAA;;;;YAIN,eAAe,MAAM;qBAEpB,mCAAO;;;IAEP,IAAE,OAAA;;;YAEH,iBAAiB,QAAQ;qBAExB,MAAI,OAAA;;;;;;;;YAQL,cAAc,KAAK;qBAElB,QAAM,OAAA;;;;;;;;;;YAUP;iBAEK;WACN,aAAa;WACb;WACA,WAAW;;WAEX;;;;;;;;;qBAaE,OAAI,SACN,uBAAqB,iBACf,aACJ,WACA,mBAAiB,SACnB;;qBAiCE,UAAO,OACX,UAAU,WAAW,gBAAc;iBAQ3B,gBAAgB,OAAO;;WAE7B,iBAAiB;;WAEjB,YAAY;WACZ,QAAQ,OAAO,UAAU,UAAU,WAAW;;WAE9C,aAAa,OAAO,UAAU;;;qBAI5B,aAAU;;;;;;qBAOV,iBAAkB,eAAa,GACvC,YAAY,gBAAc,OACtB,UAAU,WAAW,gBAAc,wBACpB,MAChB,UAAQ,kBACE,UACN,eAAe,kBACxB,cAAc,UAAU;;;;;;;;;;;;qBAkBd,WACV,sBAAoB,UAAY,gBAAgB,QAAQ,QAAM,MAAQ,UACtE,OAAK,OAAS,WACd,0BAA0B,KAAK,QAAQ,UAAS,eAAa,SACnD,gBAAgB,OAAO,WAC/B,SAAS,cAAc,OAAO,OAAO"}
@@ -0,0 +1,142 @@
1
+ import { Option, Schema } from "effect";
2
+ import { defineMessageUnion } from "foldkit/message";
3
+ import { Bundle } from "foldkit-bundle";
4
+ import { perInput } from "../internal.js";
5
+ import { Behavior, Capability } from "foldkit-mixins";
6
+ // src/interaction/roving-tabindex.ts
7
+ /**
8
+ * One tab stop for a set of items (a toolbar, a tab list, a listbox): arrows
9
+ * move focus between them, the rest stay out of the tab order. The current
10
+ * item's id is the Model slice, so a reorder keeps the same item current and a
11
+ * resumed page knows where focus was. Which item comes next is a pure
12
+ * function of the items and the key; the Behavior wires it to the slots.
13
+ */
14
+ const Orientation = Schema.Literals([
15
+ "vertical",
16
+ "horizontal",
17
+ "both"
18
+ ]);
19
+ const Model = Schema.Struct({
20
+ /** The current item's id, or `null` before any item has been focused. */
21
+ current: Schema.NullOr(Schema.String) });
22
+ const Message = defineMessageUnion({
23
+ /** An item became current: the user focused it, or a key moved there. */
24
+ Focused: { id: Schema.String } });
25
+ const Args = Schema.Struct({
26
+ orientation: Orientation,
27
+ /** Wrap from the last enabled item to the first, and back. */
28
+ loop: Schema.Boolean,
29
+ /** Keep DOM focus on the container and point at the current item with
30
+ * `aria-activedescendant` instead of moving focus. */
31
+ virtual: Schema.Boolean
32
+ });
33
+ const bundle = Bundle.make("RovingTabindex", {
34
+ Model,
35
+ Message,
36
+ args: Args,
37
+ init: () => ({ model: { current: null } }),
38
+ update: (model, message) => model.current === message.id ? { model } : { model: { current: message.id } }
39
+ });
40
+ const isPlain = (modifiers) => !modifiers.ctrlKey && !modifiers.altKey && !modifiers.metaKey;
41
+ /**
42
+ * The index the key moves to from `current`, over the enabled indices only, or
43
+ * `undefined` when the key is not a navigation key here. `current` may be
44
+ * `-1` (nothing current yet): arrows then land on the first or last enabled
45
+ * item. Under `rtl`, left and right swap. PageUp and PageDown move by `page`
46
+ * and clamp at the ends, never wrapping.
47
+ */
48
+ const move = (enabled, current, key, modifiers, options) => {
49
+ if (enabled.length === 0 || !isPlain(modifiers)) return void 0;
50
+ const first = enabled[0];
51
+ const last = enabled[enabled.length - 1];
52
+ if (key === "Home") return first;
53
+ if (key === "End") return last;
54
+ if (options.page !== void 0 && (key === "PageUp" || key === "PageDown")) {
55
+ const position = enabled.indexOf(current);
56
+ if (position === -1) return key === "PageDown" ? first : last;
57
+ const jumped = position + (key === "PageDown" ? options.page : -options.page);
58
+ return enabled[Math.min(enabled.length - 1, Math.max(0, jumped))];
59
+ }
60
+ const vertical = options.orientation !== "horizontal";
61
+ const horizontal = options.orientation !== "vertical";
62
+ const forwardKey = options.direction === "rtl" ? "ArrowLeft" : "ArrowRight";
63
+ const backwardKey = options.direction === "rtl" ? "ArrowRight" : "ArrowLeft";
64
+ const step = vertical && key === "ArrowDown" || horizontal && key === forwardKey ? 1 : vertical && key === "ArrowUp" || horizontal && key === backwardKey ? -1 : 0;
65
+ if (step === 0) return void 0;
66
+ const position = enabled.indexOf(current);
67
+ if (position === -1) return step === 1 ? first : last;
68
+ const next = position + step;
69
+ if (next < 0) return options.loop ? last : first;
70
+ if (next >= enabled.length) return options.loop ? first : last;
71
+ return enabled[next];
72
+ };
73
+ /** The item that holds the tab stop: the current one, else the first enabled. */
74
+ const tabStop = (items, current) => {
75
+ const index = current === null ? -1 : items.indexOf(current);
76
+ if (index !== -1 && !items.isDisabled(index)) return index;
77
+ return items.enabled[0] ?? -1;
78
+ };
79
+ /** A selector for an element by id, safe for any id. */
80
+ const idSelector = (id) => `[id="${id.replace(/["\\]/g, "\\$&")}"]`;
81
+ /**
82
+ * The attributes one item gets: `tabindex` 0 when it holds the tab stop and
83
+ * -1 otherwise (none under `virtual`), and `OnFocus` reporting it current.
84
+ * Shared with `ListNavigation`.
85
+ */
86
+ const itemAttributes = (h, items, current, item, virtual, focused) => {
87
+ const id = item.id ?? items.ids[item.index];
88
+ if (id === void 0) return [];
89
+ const isStop = tabStop(items, current) === item.index;
90
+ return [...virtual ? [] : [h.Tabindex(isStop ? 0 : -1)], h.OnFocus(focused(id))];
91
+ };
92
+ /**
93
+ * Wires a placed `RovingTabindex` to the slots: the container's arrow, Home
94
+ * and End keys focus the next item (synchronously, then dispatch), each item
95
+ * gets `tabindex` 0 or -1 and reports `Focused` when focused. Under `virtual`
96
+ * DOM focus never leaves the container: the key only dispatches, the
97
+ * container carries `aria-activedescendant`, and items keep no `tabindex`.
98
+ *
99
+ * Every handled key is default-prevented. Nothing is written on dispose: the
100
+ * attributes are data, so a view that no longer attaches this leaves no
101
+ * `tabindex` behind.
102
+ */
103
+ const behavior = (declared, args) => (slots) => (options) => {
104
+ const wrap = (id) => declared.wrapper.make(Message.Focused({ id }));
105
+ const slice = (input) => input[declared.field];
106
+ const itemsOf = perInput(options.items);
107
+ return Behavior.forSlots(slots)({
108
+ [options.container]: Behavior.slot({
109
+ requires: { capability: Capability.Interactive },
110
+ attributes: ({ input, h }) => {
111
+ const items = itemsOf(input);
112
+ const current = slice(input).current;
113
+ const from = current === null ? -1 : items.indexOf(current);
114
+ const direction = options.direction?.(input) ?? "ltr";
115
+ const stop = tabStop(items, current);
116
+ const stopId = stop === -1 ? void 0 : items.ids[stop];
117
+ const target = (key, modifiers) => {
118
+ const next = move(items.enabled, from, key, modifiers, {
119
+ ...args,
120
+ direction
121
+ });
122
+ return next === void 0 ? void 0 : items.ids[next];
123
+ };
124
+ if (args.virtual) return [h.OnKeyDownPreventDefault((key, modifiers) => Option.map(Option.fromNullishOr(target(key, modifiers)), wrap)), ...stopId === void 0 ? [] : [h.AriaActiveDescendant(stopId)]];
125
+ return [h.OnKeyDownFocus((key, modifiers) => Option.map(Option.fromNullishOr(target(key, modifiers)), (id) => ({
126
+ focusSelector: idSelector(id),
127
+ message: wrap(id)
128
+ })))];
129
+ }
130
+ }),
131
+ [options.item]: Behavior.slot({
132
+ requires: { capability: Capability.Focusable },
133
+ attributes: ({ input, h, item }) => {
134
+ if (item === void 0) return [];
135
+ return itemAttributes(h, itemsOf(input), slice(input).current, item, args.virtual, wrap);
136
+ }
137
+ })
138
+ }, { name: "RovingTabindex" });
139
+ };
140
+ export { Args, Message, Model, Orientation, behavior, bundle, idSelector, itemAttributes, move, tabStop };
141
+
142
+ //# sourceMappingURL=roving-tabindex.js.map