svelte-ag 0.0.2-dev.72

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 (313) hide show
  1. package/README.md +6 -0
  2. package/dist/app.css +209 -0
  3. package/dist/app.d.ts +13 -0
  4. package/dist/app.html +12 -0
  5. package/dist/icons.css +6 -0
  6. package/dist/lib/bits/internal/arrays.d.ts +95 -0
  7. package/dist/lib/bits/internal/arrays.js +250 -0
  8. package/dist/lib/bits/internal/arrays.test.d.ts +1 -0
  9. package/dist/lib/bits/internal/arrays.test.js +366 -0
  10. package/dist/lib/bits/internal/attrs.d.ts +22 -0
  11. package/dist/lib/bits/internal/attrs.js +69 -0
  12. package/dist/lib/bits/internal/box-auto-reset.svelte.d.ts +8 -0
  13. package/dist/lib/bits/internal/box-auto-reset.svelte.js +31 -0
  14. package/dist/lib/bits/internal/box.svelte.d.ts +21 -0
  15. package/dist/lib/bits/internal/box.svelte.js +26 -0
  16. package/dist/lib/bits/internal/clamp.d.ts +4 -0
  17. package/dist/lib/bits/internal/clamp.js +6 -0
  18. package/dist/lib/bits/internal/clamp.test.d.ts +1 -0
  19. package/dist/lib/bits/internal/clamp.test.js +31 -0
  20. package/dist/lib/bits/internal/create-event-hook.svelte.d.ts +18 -0
  21. package/dist/lib/bits/internal/create-event-hook.svelte.js +29 -0
  22. package/dist/lib/bits/internal/create-shared-hook.svelte.d.ts +2 -0
  23. package/dist/lib/bits/internal/create-shared-hook.svelte.js +27 -0
  24. package/dist/lib/bits/internal/date-time/announcer.d.ts +7 -0
  25. package/dist/lib/bits/internal/date-time/announcer.js +82 -0
  26. package/dist/lib/bits/internal/date-time/calendar-helpers.svelte.d.ts +201 -0
  27. package/dist/lib/bits/internal/date-time/calendar-helpers.svelte.js +510 -0
  28. package/dist/lib/bits/internal/date-time/field/helpers.d.ts +76 -0
  29. package/dist/lib/bits/internal/date-time/field/helpers.js +378 -0
  30. package/dist/lib/bits/internal/date-time/field/parts.d.ts +6 -0
  31. package/dist/lib/bits/internal/date-time/field/parts.js +9 -0
  32. package/dist/lib/bits/internal/date-time/field/segments.d.ts +51 -0
  33. package/dist/lib/bits/internal/date-time/field/segments.js +128 -0
  34. package/dist/lib/bits/internal/date-time/field/types.d.ts +25 -0
  35. package/dist/lib/bits/internal/date-time/field/types.js +1 -0
  36. package/dist/lib/bits/internal/date-time/formatter.d.ts +24 -0
  37. package/dist/lib/bits/internal/date-time/formatter.js +97 -0
  38. package/dist/lib/bits/internal/date-time/placeholders.d.ts +8 -0
  39. package/dist/lib/bits/internal/date-time/placeholders.js +129 -0
  40. package/dist/lib/bits/internal/date-time/utils.d.ts +69 -0
  41. package/dist/lib/bits/internal/date-time/utils.js +212 -0
  42. package/dist/lib/bits/internal/debounce.d.ts +4 -0
  43. package/dist/lib/bits/internal/debounce.js +19 -0
  44. package/dist/lib/bits/internal/debounce.test.d.ts +1 -0
  45. package/dist/lib/bits/internal/debounce.test.js +50 -0
  46. package/dist/lib/bits/internal/dom.d.ts +10 -0
  47. package/dist/lib/bits/internal/dom.js +38 -0
  48. package/dist/lib/bits/internal/elements.d.ts +2 -0
  49. package/dist/lib/bits/internal/elements.js +6 -0
  50. package/dist/lib/bits/internal/events.d.ts +21 -0
  51. package/dist/lib/bits/internal/events.js +49 -0
  52. package/dist/lib/bits/internal/floating-svelte/floating-utils.svelte.d.ts +7 -0
  53. package/dist/lib/bits/internal/floating-svelte/floating-utils.svelte.js +24 -0
  54. package/dist/lib/bits/internal/floating-svelte/types.d.ts +85 -0
  55. package/dist/lib/bits/internal/floating-svelte/types.js +1 -0
  56. package/dist/lib/bits/internal/floating-svelte/use-floating.svelte.d.ts +2 -0
  57. package/dist/lib/bits/internal/floating-svelte/use-floating.svelte.js +112 -0
  58. package/dist/lib/bits/internal/focus.d.ts +46 -0
  59. package/dist/lib/bits/internal/focus.js +109 -0
  60. package/dist/lib/bits/internal/get-directional-keys.d.ts +21 -0
  61. package/dist/lib/bits/internal/get-directional-keys.js +37 -0
  62. package/dist/lib/bits/internal/get-directional-keys.test.d.ts +1 -0
  63. package/dist/lib/bits/internal/get-directional-keys.test.js +46 -0
  64. package/dist/lib/bits/internal/is.d.ts +25 -0
  65. package/dist/lib/bits/internal/is.js +62 -0
  66. package/dist/lib/bits/internal/is.test.d.ts +1 -0
  67. package/dist/lib/bits/internal/is.test.js +34 -0
  68. package/dist/lib/bits/internal/kbd-constants.d.ts +40 -0
  69. package/dist/lib/bits/internal/kbd-constants.js +40 -0
  70. package/dist/lib/bits/internal/kbd.d.ts +1 -0
  71. package/dist/lib/bits/internal/kbd.js +1 -0
  72. package/dist/lib/bits/internal/locale.d.ts +6 -0
  73. package/dist/lib/bits/internal/locale.js +9 -0
  74. package/dist/lib/bits/internal/math.d.ts +5 -0
  75. package/dist/lib/bits/internal/math.js +43 -0
  76. package/dist/lib/bits/internal/math.test.d.ts +1 -0
  77. package/dist/lib/bits/internal/math.test.js +71 -0
  78. package/dist/lib/bits/internal/noop.d.ts +4 -0
  79. package/dist/lib/bits/internal/noop.js +4 -0
  80. package/dist/lib/bits/internal/should-trap-focus.d.ts +6 -0
  81. package/dist/lib/bits/internal/should-trap-focus.js +6 -0
  82. package/dist/lib/bits/internal/sleep.d.ts +1 -0
  83. package/dist/lib/bits/internal/sleep.js +3 -0
  84. package/dist/lib/bits/internal/tabbable.d.ts +10 -0
  85. package/dist/lib/bits/internal/tabbable.js +66 -0
  86. package/dist/lib/bits/internal/types.d.ts +92 -0
  87. package/dist/lib/bits/internal/types.js +1 -0
  88. package/dist/lib/bits/internal/use-after-animations.svelte.d.ts +5 -0
  89. package/dist/lib/bits/internal/use-after-animations.svelte.js +27 -0
  90. package/dist/lib/bits/internal/use-arrow-navigation.d.ts +62 -0
  91. package/dist/lib/bits/internal/use-arrow-navigation.js +76 -0
  92. package/dist/lib/bits/internal/use-body-scroll-lock.svelte.d.ts +6 -0
  93. package/dist/lib/bits/internal/use-body-scroll-lock.svelte.js +106 -0
  94. package/dist/lib/bits/internal/use-data-typeahead.svelte.d.ts +14 -0
  95. package/dist/lib/bits/internal/use-data-typeahead.svelte.js +31 -0
  96. package/dist/lib/bits/internal/use-dom-typeahead.svelte.d.ts +11 -0
  97. package/dist/lib/bits/internal/use-dom-typeahead.svelte.js +30 -0
  98. package/dist/lib/bits/internal/use-form-control.svelte.d.ts +4 -0
  99. package/dist/lib/bits/internal/use-form-control.svelte.js +16 -0
  100. package/dist/lib/bits/internal/use-grace-area.svelte.d.ts +12 -0
  101. package/dist/lib/bits/internal/use-grace-area.svelte.js +197 -0
  102. package/dist/lib/bits/internal/use-id.d.ts +4 -0
  103. package/dist/lib/bits/internal/use-id.js +8 -0
  104. package/dist/lib/bits/internal/use-resize-observer.svelte.d.ts +2 -0
  105. package/dist/lib/bits/internal/use-resize-observer.svelte.js +17 -0
  106. package/dist/lib/bits/internal/use-roving-focus.svelte.d.ts +38 -0
  107. package/dist/lib/bits/internal/use-roving-focus.svelte.js +91 -0
  108. package/dist/lib/bits/internal/use-size.svelte.d.ts +7 -0
  109. package/dist/lib/bits/internal/use-size.svelte.js +54 -0
  110. package/dist/lib/bits/internal/use-state-machine.svelte.d.ts +24 -0
  111. package/dist/lib/bits/internal/use-state-machine.svelte.js +28 -0
  112. package/dist/lib/bits/internal/use-timeout-fn.svelte.d.ts +25 -0
  113. package/dist/lib/bits/internal/use-timeout-fn.svelte.js +39 -0
  114. package/dist/lib/components/Typeahead.svelte.d.ts +47 -0
  115. package/dist/lib/components/Typeahead.svelte.js +150 -0
  116. package/dist/lib/components/animated/animated.svelte +244 -0
  117. package/dist/lib/components/animated/animated.svelte.d.ts +61 -0
  118. package/dist/lib/components/animated/index.d.ts +2 -0
  119. package/dist/lib/components/animated/index.js +2 -0
  120. package/dist/lib/components/combo/combo.svelte +186 -0
  121. package/dist/lib/components/combo/combo.svelte.d.ts +21 -0
  122. package/dist/lib/components/combo/index.d.ts +2 -0
  123. package/dist/lib/components/combo/index.js +2 -0
  124. package/dist/lib/components/dnd/Droppable.svelte +25 -0
  125. package/dist/lib/components/dnd/Droppable.svelte.d.ts +10 -0
  126. package/dist/lib/components/dnd/context.svelte.d.ts +22 -0
  127. package/dist/lib/components/dnd/context.svelte.js +25 -0
  128. package/dist/lib/components/dnd/dnd-context.svelte +45 -0
  129. package/dist/lib/components/dnd/dnd-context.svelte.d.ts +30 -0
  130. package/dist/lib/components/dnd/dnd-drag-overlay.svelte +44 -0
  131. package/dist/lib/components/dnd/dnd-drag-overlay.svelte.d.ts +27 -0
  132. package/dist/lib/components/dnd/dnd-drag-placeholder.svelte +24 -0
  133. package/dist/lib/components/dnd/dnd-drag-placeholder.svelte.d.ts +9 -0
  134. package/dist/lib/components/dnd/dnd-draghandle.svelte +30 -0
  135. package/dist/lib/components/dnd/dnd-draghandle.svelte.d.ts +6 -0
  136. package/dist/lib/components/dnd/dnd-overlay.svelte +0 -0
  137. package/dist/lib/components/dnd/dnd-overlay.svelte.d.ts +26 -0
  138. package/dist/lib/components/dnd/dnd-sortable-context.svelte +18 -0
  139. package/dist/lib/components/dnd/dnd-sortable-context.svelte.d.ts +8 -0
  140. package/dist/lib/components/dnd/dnd-sortable-item.svelte +68 -0
  141. package/dist/lib/components/dnd/dnd-sortable-item.svelte.d.ts +23 -0
  142. package/dist/lib/components/dnd/example.svelte +109 -0
  143. package/dist/lib/components/dnd/example.svelte.d.ts +3 -0
  144. package/dist/lib/components/dnd/exports.d.ts +9 -0
  145. package/dist/lib/components/dnd/exports.js +9 -0
  146. package/dist/lib/components/dnd/index.d.ts +1 -0
  147. package/dist/lib/components/dnd/index.js +1 -0
  148. package/dist/lib/components/dnd/sortable.svelte.d.ts +13 -0
  149. package/dist/lib/components/dnd/sortable.svelte.js +70 -0
  150. package/dist/lib/components/dnd/utils.svelte.d.ts +20 -0
  151. package/dist/lib/components/dnd/utils.svelte.js +20 -0
  152. package/dist/lib/components/search/combinations/searchPopover.svelte +68 -0
  153. package/dist/lib/components/search/combinations/searchPopover.svelte.d.ts +22 -0
  154. package/dist/lib/components/search/components/search-empty.svelte +28 -0
  155. package/dist/lib/components/search/components/search-empty.svelte.d.ts +4 -0
  156. package/dist/lib/components/search/components/search-input.svelte +53 -0
  157. package/dist/lib/components/search/components/search-input.svelte.d.ts +4 -0
  158. package/dist/lib/components/search/components/search-list.svelte +46 -0
  159. package/dist/lib/components/search/components/search-list.svelte.d.ts +4 -0
  160. package/dist/lib/components/search/components/search-pagnation.svelte +68 -0
  161. package/dist/lib/components/search/components/search-pagnation.svelte.d.ts +8 -0
  162. package/dist/lib/components/search/components/search.svelte +47 -0
  163. package/dist/lib/components/search/components/search.svelte.d.ts +4 -0
  164. package/dist/lib/components/search/exports.d.ts +6 -0
  165. package/dist/lib/components/search/exports.js +5 -0
  166. package/dist/lib/components/search/index.d.ts +2 -0
  167. package/dist/lib/components/search/index.js +2 -0
  168. package/dist/lib/components/search/search.svelte.d.ts +102 -0
  169. package/dist/lib/components/search/search.svelte.js +202 -0
  170. package/dist/lib/components/search/types.d.ts +28 -0
  171. package/dist/lib/components/search/types.js +1 -0
  172. package/dist/lib/components/utilities/arrow/arrow.svelte +23 -0
  173. package/dist/lib/components/utilities/arrow/arrow.svelte.d.ts +3 -0
  174. package/dist/lib/components/utilities/arrow/index.d.ts +2 -0
  175. package/dist/lib/components/utilities/arrow/index.js +1 -0
  176. package/dist/lib/components/utilities/arrow/types.d.ts +17 -0
  177. package/dist/lib/components/utilities/arrow/types.js +1 -0
  178. package/dist/lib/components/utilities/floating-layer/components/floating-layer-anchor.svelte +15 -0
  179. package/dist/lib/components/utilities/floating-layer/components/floating-layer-anchor.svelte.d.ts +4 -0
  180. package/dist/lib/components/utilities/floating-layer/components/floating-layer-arrow.svelte +20 -0
  181. package/dist/lib/components/utilities/floating-layer/components/floating-layer-arrow.svelte.d.ts +3 -0
  182. package/dist/lib/components/utilities/floating-layer/components/floating-layer-content-static.svelte +19 -0
  183. package/dist/lib/components/utilities/floating-layer/components/floating-layer-content-static.svelte.d.ts +13 -0
  184. package/dist/lib/components/utilities/floating-layer/components/floating-layer-content.svelte +61 -0
  185. package/dist/lib/components/utilities/floating-layer/components/floating-layer-content.svelte.d.ts +4 -0
  186. package/dist/lib/components/utilities/floating-layer/components/floating-layer.svelte +10 -0
  187. package/dist/lib/components/utilities/floating-layer/components/floating-layer.svelte.d.ts +7 -0
  188. package/dist/lib/components/utilities/floating-layer/components/index.d.ts +6 -0
  189. package/dist/lib/components/utilities/floating-layer/components/index.js +5 -0
  190. package/dist/lib/components/utilities/floating-layer/index.d.ts +1 -0
  191. package/dist/lib/components/utilities/floating-layer/index.js +1 -0
  192. package/dist/lib/components/utilities/floating-layer/types.d.ts +115 -0
  193. package/dist/lib/components/utilities/floating-layer/types.js +1 -0
  194. package/dist/lib/components/utilities/floating-layer/use-floating-layer.svelte.d.ts +118 -0
  195. package/dist/lib/components/utilities/floating-layer/use-floating-layer.svelte.js +311 -0
  196. package/dist/lib/index.d.ts +1 -0
  197. package/dist/lib/index.js +1 -0
  198. package/dist/lib/utils/asyncDerived.svelte.d.ts +12 -0
  199. package/dist/lib/utils/asyncDerived.svelte.js +26 -0
  200. package/dist/lib/utils/bits.d.ts +39 -0
  201. package/dist/lib/utils/bits.js +69 -0
  202. package/dist/lib/utils/index.d.ts +3 -0
  203. package/dist/lib/utils/index.js +3 -0
  204. package/dist/lib/utils/utils.d.ts +21 -0
  205. package/dist/lib/utils/utils.js +72 -0
  206. package/dist/routes/+layout.svelte +0 -0
  207. package/dist/routes/+layout.svelte.d.ts +26 -0
  208. package/package.json +79 -0
  209. package/src/app.css +209 -0
  210. package/src/app.d.ts +13 -0
  211. package/src/app.html +12 -0
  212. package/src/icons.css +6 -0
  213. package/src/lib/bits/internal/arrays.test.ts +460 -0
  214. package/src/lib/bits/internal/arrays.ts +301 -0
  215. package/src/lib/bits/internal/attrs.ts +97 -0
  216. package/src/lib/bits/internal/box-auto-reset.svelte.ts +40 -0
  217. package/src/lib/bits/internal/box.svelte.ts +60 -0
  218. package/src/lib/bits/internal/clamp.test.ts +37 -0
  219. package/src/lib/bits/internal/clamp.ts +6 -0
  220. package/src/lib/bits/internal/create-event-hook.svelte.ts +64 -0
  221. package/src/lib/bits/internal/create-shared-hook.svelte.ts +33 -0
  222. package/src/lib/bits/internal/date-time/announcer.ts +88 -0
  223. package/src/lib/bits/internal/date-time/calendar-helpers.svelte.ts +815 -0
  224. package/src/lib/bits/internal/date-time/field/helpers.ts +441 -0
  225. package/src/lib/bits/internal/date-time/field/parts.ts +9 -0
  226. package/src/lib/bits/internal/date-time/field/segments.ts +126 -0
  227. package/src/lib/bits/internal/date-time/field/types.ts +35 -0
  228. package/src/lib/bits/internal/date-time/formatter.ts +116 -0
  229. package/src/lib/bits/internal/date-time/placeholders.ts +143 -0
  230. package/src/lib/bits/internal/date-time/utils.ts +261 -0
  231. package/src/lib/bits/internal/debounce.test.ts +67 -0
  232. package/src/lib/bits/internal/debounce.ts +22 -0
  233. package/src/lib/bits/internal/dom.ts +47 -0
  234. package/src/lib/bits/internal/elements.ts +7 -0
  235. package/src/lib/bits/internal/events.ts +89 -0
  236. package/src/lib/bits/internal/floating-svelte/floating-utils.svelte.ts +28 -0
  237. package/src/lib/bits/internal/floating-svelte/types.ts +108 -0
  238. package/src/lib/bits/internal/floating-svelte/use-floating.svelte.ts +133 -0
  239. package/src/lib/bits/internal/focus.ts +111 -0
  240. package/src/lib/bits/internal/get-directional-keys.test.ts +51 -0
  241. package/src/lib/bits/internal/get-directional-keys.ts +43 -0
  242. package/src/lib/bits/internal/is.test.ts +40 -0
  243. package/src/lib/bits/internal/is.ts +78 -0
  244. package/src/lib/bits/internal/kbd-constants.ts +40 -0
  245. package/src/lib/bits/internal/kbd.ts +1 -0
  246. package/src/lib/bits/internal/locale.ts +13 -0
  247. package/src/lib/bits/internal/math.test.ts +88 -0
  248. package/src/lib/bits/internal/math.ts +50 -0
  249. package/src/lib/bits/internal/noop.ts +4 -0
  250. package/src/lib/bits/internal/should-trap-focus.ts +16 -0
  251. package/src/lib/bits/internal/sleep.ts +3 -0
  252. package/src/lib/bits/internal/tabbable.ts +76 -0
  253. package/src/lib/bits/internal/types.ts +91 -0
  254. package/src/lib/bits/internal/use-after-animations.svelte.ts +30 -0
  255. package/src/lib/bits/internal/use-arrow-navigation.ts +168 -0
  256. package/src/lib/bits/internal/use-body-scroll-lock.svelte.ts +138 -0
  257. package/src/lib/bits/internal/use-data-typeahead.svelte.ts +44 -0
  258. package/src/lib/bits/internal/use-dom-typeahead.svelte.ts +44 -0
  259. package/src/lib/bits/internal/use-form-control.svelte.ts +17 -0
  260. package/src/lib/bits/internal/use-grace-area.svelte.ts +229 -0
  261. package/src/lib/bits/internal/use-id.ts +9 -0
  262. package/src/lib/bits/internal/use-resize-observer.svelte.ts +19 -0
  263. package/src/lib/bits/internal/use-roving-focus.svelte.ts +141 -0
  264. package/src/lib/bits/internal/use-size.svelte.ts +60 -0
  265. package/src/lib/bits/internal/use-state-machine.svelte.ts +46 -0
  266. package/src/lib/bits/internal/use-timeout-fn.svelte.ts +80 -0
  267. package/src/lib/components/Typeahead.svelte.ts +200 -0
  268. package/src/lib/components/animated/animated.svelte +244 -0
  269. package/src/lib/components/animated/index.ts +3 -0
  270. package/src/lib/components/combo/combo.svelte +186 -0
  271. package/src/lib/components/combo/index.ts +3 -0
  272. package/src/lib/components/dnd/Droppable.svelte +25 -0
  273. package/src/lib/components/dnd/context.svelte.ts +30 -0
  274. package/src/lib/components/dnd/dnd-context.svelte +45 -0
  275. package/src/lib/components/dnd/dnd-drag-overlay.svelte +44 -0
  276. package/src/lib/components/dnd/dnd-drag-placeholder.svelte +24 -0
  277. package/src/lib/components/dnd/dnd-draghandle.svelte +30 -0
  278. package/src/lib/components/dnd/dnd-overlay.svelte +0 -0
  279. package/src/lib/components/dnd/dnd-sortable-context.svelte +18 -0
  280. package/src/lib/components/dnd/dnd-sortable-item.svelte +68 -0
  281. package/src/lib/components/dnd/example.svelte +109 -0
  282. package/src/lib/components/dnd/exports.ts +12 -0
  283. package/src/lib/components/dnd/index.ts +1 -0
  284. package/src/lib/components/dnd/sortable.svelte.ts +82 -0
  285. package/src/lib/components/dnd/utils.svelte.ts +29 -0
  286. package/src/lib/components/search/combinations/searchPopover.svelte +68 -0
  287. package/src/lib/components/search/components/search-empty.svelte +28 -0
  288. package/src/lib/components/search/components/search-input.svelte +53 -0
  289. package/src/lib/components/search/components/search-list.svelte +46 -0
  290. package/src/lib/components/search/components/search-pagnation.svelte +68 -0
  291. package/src/lib/components/search/components/search.svelte +47 -0
  292. package/src/lib/components/search/exports.ts +13 -0
  293. package/src/lib/components/search/index.ts +2 -0
  294. package/src/lib/components/search/search.svelte.ts +286 -0
  295. package/src/lib/components/search/types.ts +48 -0
  296. package/src/lib/components/utilities/arrow/arrow.svelte +23 -0
  297. package/src/lib/components/utilities/arrow/index.ts +2 -0
  298. package/src/lib/components/utilities/arrow/types.ts +20 -0
  299. package/src/lib/components/utilities/floating-layer/components/floating-layer-anchor.svelte +15 -0
  300. package/src/lib/components/utilities/floating-layer/components/floating-layer-arrow.svelte +20 -0
  301. package/src/lib/components/utilities/floating-layer/components/floating-layer-content-static.svelte +19 -0
  302. package/src/lib/components/utilities/floating-layer/components/floating-layer-content.svelte +61 -0
  303. package/src/lib/components/utilities/floating-layer/components/floating-layer.svelte +10 -0
  304. package/src/lib/components/utilities/floating-layer/components/index.ts +11 -0
  305. package/src/lib/components/utilities/floating-layer/index.ts +1 -0
  306. package/src/lib/components/utilities/floating-layer/types.ts +133 -0
  307. package/src/lib/components/utilities/floating-layer/use-floating-layer.svelte.ts +406 -0
  308. package/src/lib/index.ts +1 -0
  309. package/src/lib/utils/asyncDerived.svelte.ts +38 -0
  310. package/src/lib/utils/bits.ts +93 -0
  311. package/src/lib/utils/index.ts +3 -0
  312. package/src/lib/utils/utils.ts +97 -0
  313. package/src/routes/+layout.svelte +0 -0
@@ -0,0 +1,89 @@
1
+ import { on } from "svelte/events";
2
+ import type { Arrayable } from "$lib/internal/types.js";
3
+
4
+ export type EventCallback<E extends Event = Event> = (event: E) => void;
5
+
6
+ type GeneralEventListener<E = Event> = (evt: E) => unknown;
7
+
8
+ export function addEventListener<E extends keyof WindowEventMap>(
9
+ target: Window,
10
+ event: Arrayable<E>,
11
+ handler: (this: Window, ev: WindowEventMap[E]) => unknown,
12
+ options?: boolean | AddEventListenerOptions
13
+ ): VoidFunction;
14
+
15
+ export function addEventListener<E extends keyof DocumentEventMap>(
16
+ target: Document,
17
+ event: Arrayable<E>,
18
+ handler: (this: Document, ev: DocumentEventMap[E]) => unknown,
19
+ options?: boolean | AddEventListenerOptions
20
+ ): VoidFunction;
21
+
22
+ export function addEventListener<E extends keyof HTMLElementEventMap>(
23
+ target: EventTarget,
24
+ event: Arrayable<E>,
25
+ handler: GeneralEventListener<HTMLElementEventMap[E]>,
26
+ options?: boolean | AddEventListenerOptions
27
+ ): VoidFunction;
28
+ /**
29
+ * Adds an event listener to the specified target element(s) for the given event(s), and returns a function to remove it.
30
+ * @param target The target element(s) to add the event listener to.
31
+ * @param event The event(s) to listen for.
32
+ * @param handler The function to be called when the event is triggered.
33
+ * @param options An optional object that specifies characteristics about the event listener.
34
+ * @returns A function that removes the event listener from the target element(s).
35
+ */
36
+ export function addEventListener(
37
+ target: Window | Document | EventTarget,
38
+ event: Arrayable<string>,
39
+ handler: EventListenerOrEventListenerObject,
40
+ options?: boolean | AddEventListenerOptions
41
+ ) {
42
+ const events = Array.isArray(event) ? event : [event];
43
+
44
+ // Add the event listener to each specified event for the target element(s).
45
+ events.forEach((_event) => target.addEventListener(_event, handler, options));
46
+
47
+ // Return a function that removes the event listener from the target element(s).
48
+ return () => {
49
+ events.forEach((_event) => target.removeEventListener(_event, handler, options));
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Creates a typed event dispatcher and listener pair for custom events
55
+ * @template T - The type of data that will be passed in the event detail
56
+ * @param eventName - The name of the custom event
57
+ * @param options - CustomEvent options (bubbles, cancelable, etc.)
58
+ */
59
+ export class CustomEventDispatcher<T = unknown> {
60
+ constructor(
61
+ readonly eventName: string,
62
+ readonly options: Omit<CustomEventInit<T>, "detail"> = { bubbles: true, cancelable: true }
63
+ ) {}
64
+
65
+ createEvent(detail?: T): CustomEvent<T> {
66
+ return new CustomEvent<T>(this.eventName, {
67
+ ...this.options,
68
+ detail,
69
+ });
70
+ }
71
+
72
+ dispatch(element: EventTarget, detail?: T): CustomEvent<T> {
73
+ const event = this.createEvent(detail);
74
+ element.dispatchEvent(event);
75
+ return event;
76
+ }
77
+
78
+ listen(
79
+ element: EventTarget,
80
+ callback: (event: CustomEvent<T>) => void,
81
+ options?: AddEventListenerOptions
82
+ ) {
83
+ const handler = (event: Event) => {
84
+ callback(event as CustomEvent<T>);
85
+ };
86
+
87
+ return on(element, this.eventName, handler, options);
88
+ }
89
+ }
@@ -0,0 +1,28 @@
1
+ import type { Getter, MaybeGetter } from "svelte-toolbelt";
2
+
3
+ export function get<T>(valueOrGetValue: MaybeGetter<T>): T {
4
+ return typeof valueOrGetValue === "function"
5
+ ? (valueOrGetValue as Getter<T>)()
6
+ : valueOrGetValue;
7
+ }
8
+
9
+ export function getDPR(element: Element): number {
10
+ if (typeof window === "undefined") return 1;
11
+ const win = element.ownerDocument.defaultView || window;
12
+ return win.devicePixelRatio || 1;
13
+ }
14
+
15
+ export function roundByDPR(element: Element, value: number) {
16
+ const dpr = getDPR(element);
17
+ return Math.round(value * dpr) / dpr;
18
+ }
19
+
20
+ export function getFloatingContentCSSVars(name: string) {
21
+ return {
22
+ [`--bits-${name}-content-transform-origin`]: `var(--bits-floating-transform-origin)`,
23
+ [`--bits-${name}-content-available-width`]: `var(--bits-floating-available-width)`,
24
+ [`--bits-${name}-content-available-height`]: `var(--bits-floating-available-height)`,
25
+ [`--bits-${name}-anchor-width`]: `var(--bits-floating-anchor-width)`,
26
+ [`--bits-${name}-anchor-height`]: `var(--bits-floating-anchor-height)`,
27
+ };
28
+ }
@@ -0,0 +1,108 @@
1
+ import type {
2
+ FloatingElement,
3
+ Middleware,
4
+ MiddlewareData,
5
+ Placement,
6
+ ReferenceElement,
7
+ Strategy,
8
+ } from "@floating-ui/dom";
9
+ import type { ReadableBox, WritableBox } from "svelte-toolbelt";
10
+
11
+ type ValueOrGetValue<T> = T | (() => T);
12
+
13
+ export type Measurable = {
14
+ getBoundingClientRect: () => DOMRect;
15
+ };
16
+
17
+ export type UseFloatingOptions = {
18
+ /**
19
+ * Represents the open/close state of the floating element.
20
+ * @default true
21
+ */
22
+ open?: ValueOrGetValue<boolean | undefined>;
23
+ /**
24
+ * Where to place the floating element relative to its reference element.
25
+ * @default 'bottom'
26
+ */
27
+ placement?: ValueOrGetValue<Placement | undefined>;
28
+ /**
29
+ * The type of CSS position property to use.
30
+ * @default 'absolute'
31
+ */
32
+ strategy?: ValueOrGetValue<Strategy | undefined>;
33
+ /**
34
+ * These are plain objects that modify the positioning coordinates in some fashion,
35
+ * or provide useful data for the consumer to use.
36
+ * @default undefined
37
+ */
38
+ middleware?: ValueOrGetValue<Middleware[] | undefined>;
39
+ /**
40
+ * Whether to use `transform` instead of `top` and `left` styles to
41
+ * position the floating element (`floatingStyles`).
42
+ * @default true
43
+ */
44
+ transform?: ValueOrGetValue<boolean | undefined>;
45
+
46
+ /**
47
+ * Reference / Anchor element to position the floating element relative to
48
+ */
49
+ reference: ReadableBox<Measurable | HTMLElement | null>;
50
+
51
+ /**
52
+ * Callback to handle mounting/unmounting of the elements.
53
+ * @default undefined
54
+ */
55
+ whileElementsMounted?: (
56
+ reference: ReferenceElement,
57
+ floating: FloatingElement,
58
+ update: () => void
59
+ ) => () => void;
60
+ };
61
+
62
+ export type UseFloatingReturn = {
63
+ /**
64
+ * The reference element to position the floating element relative to.
65
+ */
66
+ reference: ReadableBox<Measurable | HTMLElement | null>;
67
+
68
+ /**
69
+ * The floating element to position.
70
+ */
71
+ floating: WritableBox<HTMLElement | null>;
72
+
73
+ /**
74
+ * The stateful placement, which can be different from the initial `placement` passed as options.
75
+ */
76
+ placement: Readonly<Placement>;
77
+
78
+ /**
79
+ * The type of CSS position property to use.
80
+ */
81
+ strategy: Readonly<Strategy>;
82
+
83
+ /**
84
+ * Additional data from middleware.
85
+ */
86
+ middlewareData: Readonly<MiddlewareData>;
87
+
88
+ /**
89
+ * The boolean that let you know if the floating element has been positioned.
90
+ */
91
+ isPositioned: Readonly<boolean>;
92
+
93
+ /**
94
+ * CSS styles to apply to the floating element to position it.
95
+ */
96
+ floatingStyles: Readonly<{
97
+ position: Strategy;
98
+ top: string;
99
+ left: string;
100
+ transform?: string;
101
+ willChange?: string;
102
+ }>;
103
+
104
+ /**
105
+ * The function to update floating position manually.
106
+ */
107
+ update: () => void;
108
+ };
@@ -0,0 +1,133 @@
1
+ import { computePosition } from "@floating-ui/dom";
2
+ import { box } from "svelte-toolbelt";
3
+ import type { UseFloatingOptions, UseFloatingReturn } from "./types.js";
4
+ import { get, getDPR, roundByDPR } from "./floating-utils.svelte.js";
5
+
6
+ export function useFloating(options: UseFloatingOptions): UseFloatingReturn {
7
+ /** Options */
8
+ const whileElementsMountedOption = options.whileElementsMounted;
9
+ const openOption = $derived(get(options.open) ?? true);
10
+ const middlewareOption = $derived(get(options.middleware));
11
+ const transformOption = $derived(get(options.transform) ?? true);
12
+ const placementOption = $derived(get(options.placement) ?? "bottom");
13
+ const strategyOption = $derived(get(options.strategy) ?? "absolute");
14
+ const reference = options.reference;
15
+
16
+ /** State */
17
+ let x = $state(0);
18
+ let y = $state(0);
19
+
20
+ const floating = box<HTMLElement | null>(null);
21
+
22
+ let strategy = $state(strategyOption);
23
+ let placement = $state(placementOption);
24
+ let middlewareData = $state({});
25
+ let isPositioned = $state(false);
26
+ const floatingStyles = $derived.by(() => {
27
+ const initialStyles = {
28
+ position: strategy,
29
+ left: "0",
30
+ top: "0",
31
+ };
32
+
33
+ if (!floating.current) {
34
+ return initialStyles;
35
+ }
36
+
37
+ const xVal = roundByDPR(floating.current, x);
38
+ const yVal = roundByDPR(floating.current, y);
39
+
40
+ if (transformOption) {
41
+ return {
42
+ ...initialStyles,
43
+ transform: `translate(${xVal}px, ${yVal}px)`,
44
+ ...(getDPR(floating.current) >= 1.5 && {
45
+ willChange: "transform",
46
+ }),
47
+ };
48
+ }
49
+
50
+ return {
51
+ position: strategy,
52
+ left: `${xVal}px`,
53
+ top: `${yVal}px`,
54
+ };
55
+ });
56
+
57
+ /** Effects */
58
+ let whileElementsMountedCleanup: (() => void) | undefined;
59
+
60
+ function update() {
61
+ if (reference.current === null || floating.current === null) return;
62
+ computePosition(reference.current, floating.current, {
63
+ middleware: middlewareOption,
64
+ placement: placementOption,
65
+ strategy: strategyOption,
66
+ }).then((position) => {
67
+ x = position.x;
68
+ y = position.y;
69
+ strategy = position.strategy;
70
+ placement = position.placement;
71
+ middlewareData = position.middlewareData;
72
+ isPositioned = true;
73
+ });
74
+ }
75
+
76
+ function cleanup() {
77
+ if (typeof whileElementsMountedCleanup === "function") {
78
+ whileElementsMountedCleanup();
79
+ whileElementsMountedCleanup = undefined;
80
+ }
81
+ }
82
+
83
+ function attach() {
84
+ cleanup();
85
+
86
+ if (whileElementsMountedOption === undefined) {
87
+ update();
88
+ return;
89
+ }
90
+
91
+ if (reference.current === null || floating.current === null) return;
92
+
93
+ whileElementsMountedCleanup = whileElementsMountedOption(
94
+ reference.current,
95
+ floating.current,
96
+ update
97
+ );
98
+ }
99
+
100
+ function reset() {
101
+ if (!openOption) {
102
+ isPositioned = false;
103
+ }
104
+ }
105
+
106
+ $effect(update);
107
+ $effect(attach);
108
+ $effect(reset);
109
+ $effect(() => cleanup);
110
+
111
+ return {
112
+ floating,
113
+ reference,
114
+ get strategy() {
115
+ return strategy;
116
+ },
117
+ get placement() {
118
+ return placement;
119
+ },
120
+ get middlewareData() {
121
+ return middlewareData;
122
+ },
123
+ get isPositioned() {
124
+ return isPositioned;
125
+ },
126
+ get floatingStyles() {
127
+ return floatingStyles;
128
+ },
129
+ get update() {
130
+ return update;
131
+ },
132
+ };
133
+ }
@@ -0,0 +1,111 @@
1
+ import { isBrowser, isElementHidden, isSelectableInput } from "./is.js";
2
+
3
+ export type FocusableTarget = HTMLElement | { focus: () => void };
4
+
5
+ /**
6
+ * Handles `initialFocus` prop behavior for the
7
+ * Calendar & RangeCalendar components.
8
+ */
9
+ export function handleCalendarInitialFocus(calendar: HTMLElement) {
10
+ if (!isBrowser) return;
11
+ const selectedDay = calendar.querySelector<HTMLElement>("[data-selected]");
12
+ if (selectedDay) return focusWithoutScroll(selectedDay);
13
+
14
+ const today = calendar.querySelector<HTMLElement>("[data-today]");
15
+ if (today) return focusWithoutScroll(today);
16
+
17
+ const firstDay = calendar.querySelector<HTMLElement>("[data-calendar-date]");
18
+ if (firstDay) return focusWithoutScroll(firstDay);
19
+ }
20
+
21
+ /**
22
+ * A utility function that focuses an element without scrolling.
23
+ */
24
+ export function focusWithoutScroll(element: HTMLElement) {
25
+ const scrollPosition = {
26
+ x: window.pageXOffset || document.documentElement.scrollLeft,
27
+ y: window.pageYOffset || document.documentElement.scrollTop,
28
+ };
29
+ element.focus();
30
+ window.scrollTo(scrollPosition.x, scrollPosition.y);
31
+ }
32
+
33
+ /**
34
+ * A utility function that focuses an element.
35
+ */
36
+ export function focus(element?: FocusableTarget | null, { select = false } = {}) {
37
+ if (!(element && element.focus)) return;
38
+ if (document.activeElement === element) return;
39
+ const previouslyFocusedElement = document.activeElement;
40
+ // prevent scroll on focus
41
+ element.focus({ preventScroll: true });
42
+ // only elect if its not the same element, it supports selection, and we need to select it
43
+ if (element !== previouslyFocusedElement && isSelectableInput(element) && select) {
44
+ element.select();
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Attempts to focus the first element in a list of candidates.
50
+ * Stops when focus is successful.
51
+ */
52
+ export function focusFirst(candidates: HTMLElement[], { select = false } = {}) {
53
+ const previouslyFocusedElement = document.activeElement;
54
+ for (const candidate of candidates) {
55
+ focus(candidate, { select });
56
+ if (document.activeElement !== previouslyFocusedElement) {
57
+ return true;
58
+ }
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Returns the first visible element in a list.
64
+ * NOTE: Only checks visibility up to the `container`.
65
+ */
66
+ export function findVisible(elements: HTMLElement[], container: HTMLElement) {
67
+ for (const element of elements) {
68
+ // we stop checking if it's hidden at the `container` level (excluding)
69
+ if (!isElementHidden(element, container)) return element;
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Returns a list of potential tabbable candidates.
75
+ *
76
+ * NOTE: This is only a close approximation. For example it doesn't take into account cases like when
77
+ * elements are not visible. This cannot be worked out easily by just reading a property, but rather
78
+ * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.
79
+ *
80
+ * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
81
+ * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1
82
+ */
83
+ export function getTabbableCandidates(container: HTMLElement) {
84
+ const nodes: HTMLElement[] = [];
85
+ const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
86
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
+ acceptNode: (node: any) => {
88
+ const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden";
89
+ if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;
90
+ // `.tabIndex` is not the same as the `tabindex` attribute. It works on the
91
+ // runtime's understanding of tabbability, so this automatically accounts
92
+ // for any kind of element that could be tabbed to.
93
+ return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
94
+ },
95
+ });
96
+ while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);
97
+ // we do not take into account the order of nodes with positive `tabIndex` as it
98
+ // hinders accessibility to have tab order different from visual order.
99
+ return nodes;
100
+ }
101
+
102
+ /**
103
+ * A utility function that returns the first and last elements within a container that are
104
+ * visible and focusable.
105
+ */
106
+ export function getTabbableEdges(container: HTMLElement) {
107
+ const candidates = getTabbableCandidates(container);
108
+ const first = findVisible(candidates, container);
109
+ const last = findVisible(candidates.reverse(), container);
110
+ return [first, last] as const;
111
+ }
@@ -0,0 +1,51 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { describe, expect, it } from "vitest";
3
+ import { getDirectionalKeys } from "./get-directional-keys.js";
4
+ import { kbd } from "./kbd.js";
5
+
6
+ describe("getDirectionalKeys", () => {
7
+ it("should return correct keys for default direction and orientation", () => {
8
+ const result = getDirectionalKeys();
9
+ expect(result).toEqual({
10
+ nextKey: kbd.ARROW_RIGHT,
11
+ prevKey: kbd.ARROW_LEFT,
12
+ });
13
+ });
14
+
15
+ it("should return correct keys for rtl direction and horizontal orientation", () => {
16
+ const result = getDirectionalKeys("rtl", "horizontal");
17
+ expect(result).toEqual({
18
+ nextKey: kbd.ARROW_LEFT,
19
+ prevKey: kbd.ARROW_RIGHT,
20
+ });
21
+ });
22
+
23
+ it("should return correct keys for ltr direction and vertical orientation", () => {
24
+ const result = getDirectionalKeys("ltr", "vertical");
25
+ expect(result).toEqual({
26
+ nextKey: kbd.ARROW_DOWN,
27
+ prevKey: kbd.ARROW_UP,
28
+ });
29
+ });
30
+
31
+ it("should return correct keys for rtl direction and vertical orientation", () => {
32
+ const result = getDirectionalKeys("rtl", "vertical");
33
+ expect(result).toEqual({
34
+ nextKey: kbd.ARROW_DOWN,
35
+ prevKey: kbd.ARROW_UP,
36
+ });
37
+ });
38
+
39
+ it("should handle invalid direction and orientation values", () => {
40
+ const result1 = getDirectionalKeys("invalid" as any, "horizontal");
41
+ const result2 = getDirectionalKeys("ltr", "invalid" as any);
42
+ expect(result1).toEqual({
43
+ nextKey: kbd.ARROW_RIGHT,
44
+ prevKey: kbd.ARROW_LEFT,
45
+ });
46
+ expect(result2).toEqual({
47
+ nextKey: kbd.ARROW_RIGHT,
48
+ prevKey: kbd.ARROW_LEFT,
49
+ });
50
+ });
51
+ });
@@ -0,0 +1,43 @@
1
+ import { kbd } from "./kbd.js";
2
+ import type { Direction, Orientation } from "$lib/shared/index.js";
3
+
4
+ export const FIRST_KEYS = [kbd.ARROW_DOWN, kbd.PAGE_UP, kbd.HOME];
5
+ export const LAST_KEYS = [kbd.ARROW_UP, kbd.PAGE_DOWN, kbd.END];
6
+ export const FIRST_LAST_KEYS = [...FIRST_KEYS, ...LAST_KEYS];
7
+ export const SELECTION_KEYS = [kbd.SPACE, kbd.ENTER];
8
+
9
+ /**
10
+ * A utility function that returns the next key based on the direction and orientation.
11
+ */
12
+ export function getNextKey(dir: Direction = "ltr", orientation: Orientation = "horizontal") {
13
+ return {
14
+ horizontal: dir === "rtl" ? kbd.ARROW_LEFT : kbd.ARROW_RIGHT,
15
+ vertical: kbd.ARROW_DOWN,
16
+ }[orientation];
17
+ }
18
+
19
+ /**
20
+ * A utility function that returns the previous key based on the direction and orientation.
21
+ */
22
+ export function getPrevKey(dir: Direction = "ltr", orientation: Orientation = "horizontal") {
23
+ return {
24
+ horizontal: dir === "rtl" ? kbd.ARROW_RIGHT : kbd.ARROW_LEFT,
25
+ vertical: kbd.ARROW_UP,
26
+ }[orientation];
27
+ }
28
+
29
+ /**
30
+ * A utility function that returns the next and previous keys based on the direction
31
+ * and orientation.
32
+ */
33
+ export function getDirectionalKeys(
34
+ dir: Direction = "ltr",
35
+ orientation: Orientation = "horizontal"
36
+ ) {
37
+ if (!["ltr", "rtl"].includes(dir)) dir = "ltr";
38
+ if (!["horizontal", "vertical"].includes(orientation)) orientation = "horizontal";
39
+ return {
40
+ nextKey: getNextKey(dir, orientation),
41
+ prevKey: getPrevKey(dir, orientation),
42
+ };
43
+ }
@@ -0,0 +1,40 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { isNumberString } from "./is.js";
3
+
4
+ describe("isNumberString", () => {
5
+ it("should return true for valid number strings", () => {
6
+ expect(isNumberString("123")).toBe(true);
7
+ expect(isNumberString("0")).toBe(true);
8
+ expect(isNumberString("-42")).toBe(true);
9
+ expect(isNumberString("3.14")).toBe(true);
10
+ });
11
+
12
+ it("should return false for strings that are not valid numbers", () => {
13
+ expect(isNumberString("abc")).toBe(false);
14
+ expect(isNumberString("1a2b3c")).toBe(false);
15
+ expect(isNumberString("number")).toBe(false);
16
+ expect(isNumberString("--123")).toBe(false);
17
+ });
18
+
19
+ it("should return false for empty string", () => {
20
+ expect(isNumberString("")).toBe(false);
21
+ });
22
+
23
+ it("should return true for strings with leading or trailing whitespace", () => {
24
+ expect(isNumberString(" 123")).toBe(true);
25
+ expect(isNumberString("456 ")).toBe(true);
26
+ expect(isNumberString(" 789 ")).toBe(true);
27
+ });
28
+
29
+ it("should return false for strings with non-numeric characters and whitespace", () => {
30
+ expect(isNumberString(" abc123")).toBe(false);
31
+ expect(isNumberString("123def ")).toBe(false);
32
+ expect(isNumberString(" 456 xyz ")).toBe(false);
33
+ });
34
+
35
+ it("should return true for strings with exponential notation", () => {
36
+ expect(isNumberString("1e3")).toBe(true);
37
+ expect(isNumberString("2.5e-4")).toBe(true);
38
+ expect(isNumberString("-3.2E+5")).toBe(true);
39
+ });
40
+ });
@@ -0,0 +1,78 @@
1
+ import type { FocusableTarget } from "./focus.js";
2
+
3
+ export const isBrowser = typeof document !== "undefined";
4
+
5
+ export const isIOS = getIsIOS();
6
+
7
+ function getIsIOS() {
8
+ return (
9
+ isBrowser &&
10
+ window?.navigator?.userAgent &&
11
+ (/iP(ad|hone|od)/.test(window.navigator.userAgent) ||
12
+ // The new iPad Pro Gen3 does not identify itself as iPad, but as Macintosh.
13
+ (window?.navigator?.maxTouchPoints > 2 &&
14
+ /iPad|Macintosh/.test(window?.navigator.userAgent)))
15
+ );
16
+ }
17
+
18
+ export function isFunction(value: unknown): value is (...args: unknown[]) => unknown {
19
+ return typeof value === "function";
20
+ }
21
+
22
+ export function isHTMLElement(element: unknown): element is HTMLElement {
23
+ return element instanceof HTMLElement;
24
+ }
25
+
26
+ export function isElement(element: unknown): element is Element {
27
+ return element instanceof Element;
28
+ }
29
+
30
+ export function isElementOrSVGElement(element: unknown): element is Element | SVGElement {
31
+ return element instanceof Element || element instanceof SVGElement;
32
+ }
33
+
34
+ export function isNumberString(value: string) {
35
+ return !Number.isNaN(Number(value)) && !Number.isNaN(Number.parseFloat(value));
36
+ }
37
+
38
+ export function isNull(value: unknown): value is null {
39
+ return value === null;
40
+ }
41
+
42
+ export function isTouch(e: PointerEvent) {
43
+ return e.pointerType === "touch";
44
+ }
45
+
46
+ export function isFocusVisible(element: Element) {
47
+ return element.matches(":focus-visible");
48
+ }
49
+
50
+ export function isNotNull<T>(value: T | null): value is T {
51
+ return value !== null;
52
+ }
53
+
54
+ /**
55
+ * Determines if the provided object is a valid `HTMLInputElement` with
56
+ * a `select` method available.
57
+ */
58
+ export function isSelectableInput(
59
+ element: unknown
60
+ ): element is FocusableTarget & { select: () => void } {
61
+ return element instanceof HTMLInputElement && "select" in element;
62
+ }
63
+
64
+ /**
65
+ * Given a node, determine if it is hidden by walking up the
66
+ * DOM tree until we hit the `stopAt` node (exclusive), if provided)
67
+ * otherwise we stop at the document root.
68
+ */
69
+ export function isElementHidden(node: HTMLElement, stopAt?: HTMLElement) {
70
+ if (getComputedStyle(node).visibility === "hidden") return true;
71
+ while (node) {
72
+ // we stop at `upTo` (excluding it)
73
+ if (stopAt !== undefined && node === stopAt) return false;
74
+ if (getComputedStyle(node).display === "none") return true;
75
+ node = node.parentElement as HTMLElement;
76
+ }
77
+ return false;
78
+ }