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,138 @@
1
+ import { SvelteMap } from "svelte/reactivity";
2
+ import { type Getter, afterSleep, afterTick, box } from "svelte-toolbelt";
3
+ import { untrack } from "svelte";
4
+ import type { Fn } from "./types.js";
5
+ import { isBrowser, isIOS } from "./is.js";
6
+ import { addEventListener } from "./events.js";
7
+ import { useId } from "./use-id.js";
8
+ import { createSharedHook } from "./create-shared-hook.svelte.js";
9
+
10
+ export type ScrollBodyOption = {
11
+ padding?: boolean | number;
12
+ margin?: boolean | number;
13
+ };
14
+
15
+ const useBodyLockStackCount = createSharedHook(() => {
16
+ const map = new SvelteMap<string, boolean>();
17
+
18
+ const locked = $derived.by(() => {
19
+ for (const value of map.values()) {
20
+ if (value) {
21
+ return true;
22
+ }
23
+ }
24
+ return false;
25
+ });
26
+
27
+ let initialBodyStyle: string | null = $state<string | null>(null);
28
+
29
+ let stopTouchMoveListener: Fn | null = null;
30
+
31
+ function resetBodyStyle() {
32
+ if (!isBrowser) return;
33
+ document.body.setAttribute("style", initialBodyStyle ?? "");
34
+ document.body.style.removeProperty("--scrollbar-width");
35
+ isIOS && stopTouchMoveListener?.();
36
+ }
37
+
38
+ $effect(() => {
39
+ const curr = locked;
40
+ return untrack(() => {
41
+ if (!curr) {
42
+ return;
43
+ }
44
+
45
+ initialBodyStyle = document.body.getAttribute("style");
46
+ const bodyStyle = getComputedStyle(document.body);
47
+
48
+ // TODO: account for RTL direction, etc.
49
+ const verticalScrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
50
+ const paddingRight = Number.parseInt(bodyStyle.paddingRight ?? "0", 10);
51
+
52
+ const config = {
53
+ padding: paddingRight + verticalScrollbarWidth,
54
+ margin: Number.parseInt(bodyStyle.marginRight ?? "0", 10),
55
+ };
56
+
57
+ if (verticalScrollbarWidth > 0) {
58
+ document.body.style.paddingRight = `${config.padding}px`;
59
+ document.body.style.marginRight = `${config.margin}px`;
60
+ document.body.style.setProperty("--scrollbar-width", `${verticalScrollbarWidth}px`);
61
+ document.body.style.overflow = "hidden";
62
+ }
63
+
64
+ if (isIOS) {
65
+ stopTouchMoveListener = addEventListener(
66
+ document,
67
+ "touchmove",
68
+ (e) => {
69
+ if (e.target !== document.documentElement) return;
70
+
71
+ if (e.touches.length > 1) return;
72
+ e.preventDefault();
73
+ },
74
+ { passive: false }
75
+ );
76
+ }
77
+
78
+ afterTick(() => {
79
+ document.body.style.pointerEvents = "none";
80
+ document.body.style.overflow = "hidden";
81
+ });
82
+ });
83
+ });
84
+
85
+ $effect(() => {
86
+ return () => {
87
+ stopTouchMoveListener?.();
88
+ };
89
+ });
90
+
91
+ return {
92
+ get map() {
93
+ return map;
94
+ },
95
+ resetBodyStyle,
96
+ };
97
+ });
98
+
99
+ export function useBodyScrollLock(
100
+ initialState?: boolean | undefined,
101
+ restoreScrollDelay: Getter<number | null> = () => null
102
+ ) {
103
+ const id = useId();
104
+ const countState = useBodyLockStackCount();
105
+ if (!countState) return;
106
+ const _restoreScrollDelay = $derived(restoreScrollDelay());
107
+
108
+ countState.map.set(id, initialState ?? false);
109
+
110
+ const locked = box.with(
111
+ () => countState.map.get(id) ?? false,
112
+ (v) => countState.map.set(id, v)
113
+ );
114
+
115
+ $effect(() => {
116
+ return () => {
117
+ countState.map.delete(id);
118
+ // if any locks are still active, we don't reset the body style
119
+ if (isAnyLocked(countState.map)) return;
120
+
121
+ // if no locks are active (meaning this was the last lock), we reset the body style
122
+ if (_restoreScrollDelay === null) {
123
+ requestAnimationFrame(() => countState.resetBodyStyle());
124
+ } else {
125
+ afterSleep(_restoreScrollDelay, () => countState.resetBodyStyle());
126
+ }
127
+ };
128
+ });
129
+
130
+ return locked;
131
+ }
132
+
133
+ function isAnyLocked(map: Map<string, boolean>) {
134
+ for (const [_, value] of map) {
135
+ if (value) return true;
136
+ }
137
+ return false;
138
+ }
@@ -0,0 +1,44 @@
1
+ import type { Getter } from "svelte-toolbelt";
2
+ import { getNextMatch } from "./arrays.js";
3
+ import { boxAutoReset } from "./box-auto-reset.svelte.js";
4
+
5
+ export type DataTypeahead = ReturnType<typeof useDataTypeahead>;
6
+
7
+ type UseDataTypeaheadOpts = {
8
+ onMatch: (value: string) => void;
9
+ getCurrentItem: () => string;
10
+ candidateValues: Getter<string[]>;
11
+ enabled: boolean;
12
+ };
13
+
14
+ export function useDataTypeahead(opts: UseDataTypeaheadOpts) {
15
+ // Reset `search` 1 second after it was last updated
16
+ const search = boxAutoReset("", 1000);
17
+ const candidateValues = $derived(opts.candidateValues());
18
+
19
+ function handleTypeaheadSearch(key: string) {
20
+ if (!opts.enabled) return;
21
+ if (!candidateValues.length) return;
22
+
23
+ search.current = search.current + key;
24
+ const currentItem = opts.getCurrentItem();
25
+ const currentMatch = candidateValues.find((item) => item === currentItem) ?? "";
26
+ const values = candidateValues.map((item) => item ?? "");
27
+ const nextMatch = getNextMatch(values, search.current, currentMatch);
28
+ const newItem = candidateValues.find((item) => item === nextMatch);
29
+ if (newItem) {
30
+ opts.onMatch(newItem);
31
+ }
32
+ return newItem;
33
+ }
34
+
35
+ function resetTypeahead() {
36
+ search.current = "";
37
+ }
38
+
39
+ return {
40
+ search,
41
+ handleTypeaheadSearch,
42
+ resetTypeahead,
43
+ };
44
+ }
@@ -0,0 +1,44 @@
1
+ import { getNextMatch } from "./arrays.js";
2
+ import { boxAutoReset } from "./box-auto-reset.svelte.js";
3
+
4
+ export type DOMTypeahead = ReturnType<typeof useDOMTypeahead>;
5
+
6
+ type UseDOMTypeaheadOpts = {
7
+ onMatch?: (item: HTMLElement) => void;
8
+ getCurrentItem?: () => HTMLElement | null;
9
+ };
10
+
11
+ export function useDOMTypeahead(opts?: UseDOMTypeaheadOpts) {
12
+ // Reset `search` 1 second after it was last updated
13
+ const search = boxAutoReset("", 1000);
14
+
15
+ const onMatch = opts?.onMatch ?? ((node) => node.focus());
16
+ const getCurrentItem =
17
+ opts?.getCurrentItem ?? (() => document.activeElement as HTMLElement | null);
18
+
19
+ function handleTypeaheadSearch(key: string, candidates: HTMLElement[]) {
20
+ if (!candidates.length) return;
21
+
22
+ search.current = search.current + key;
23
+ const currentItem = getCurrentItem();
24
+
25
+ const currentMatch = candidates.find((item) => item === currentItem)?.textContent ?? "";
26
+ const values = candidates.map((item) => item.textContent ?? "");
27
+ const nextMatch = getNextMatch(values, search.current, currentMatch);
28
+ const newItem = candidates.find((item) => item.textContent === nextMatch);
29
+ if (newItem) {
30
+ onMatch(newItem);
31
+ }
32
+ return newItem;
33
+ }
34
+
35
+ function resetTypeahead() {
36
+ search.current = "";
37
+ }
38
+
39
+ return {
40
+ search,
41
+ handleTypeaheadSearch,
42
+ resetTypeahead,
43
+ };
44
+ }
@@ -0,0 +1,17 @@
1
+ import type { Getter } from "svelte-toolbelt";
2
+ import { isBrowser } from "./is.js";
3
+
4
+ export function useFormControl(getNode: Getter<HTMLElement | null>) {
5
+ const isInForm = $derived.by(() => {
6
+ if (!isBrowser) return false;
7
+ const node = getNode();
8
+ if (!node) return false;
9
+ return Boolean(node.closest("form"));
10
+ });
11
+
12
+ return {
13
+ get current() {
14
+ return isInForm;
15
+ },
16
+ };
17
+ }
@@ -0,0 +1,229 @@
1
+ import { type Getter, executeCallbacks } from "svelte-toolbelt";
2
+ import { on } from "svelte/events";
3
+ import { watch } from "runed";
4
+ import { boxAutoReset } from "./box-auto-reset.svelte.js";
5
+ import { isElement, isHTMLElement } from "./is.js";
6
+ import type { Side } from "$lib/bits/utilities/floating-layer/use-floating-layer.svelte.js";
7
+ interface UseGraceAreaOpts {
8
+ enabled: Getter<boolean>;
9
+ triggerNode: Getter<HTMLElement | null>;
10
+ contentNode: Getter<HTMLElement | null>;
11
+ onPointerExit: () => void;
12
+ setIsPointerInTransit?: (value: boolean) => void;
13
+ }
14
+ export function useGraceArea(opts: UseGraceAreaOpts) {
15
+ const enabled = $derived(opts.enabled());
16
+
17
+ const isPointerInTransit = boxAutoReset(false as boolean, 300, (value) => {
18
+ if (enabled) {
19
+ opts.setIsPointerInTransit?.(value);
20
+ }
21
+ });
22
+
23
+ let pointerGraceArea = $state<Polygon | null>(null);
24
+
25
+ function handleRemoveGraceArea() {
26
+ pointerGraceArea = null;
27
+ isPointerInTransit.current = false;
28
+ }
29
+
30
+ function handleCreateGraceArea(e: PointerEvent, hoverTarget: HTMLElement) {
31
+ const currentTarget = e.currentTarget;
32
+ if (!isHTMLElement(currentTarget)) return;
33
+ const exitPoint = { x: e.clientX, y: e.clientY };
34
+ const exitSide = getExitSideFromRect(exitPoint, currentTarget.getBoundingClientRect());
35
+ const paddedExitPoints = getPaddedExitPoints(exitPoint, exitSide);
36
+ const hoverTargetPoints = getPointsFromRect(hoverTarget.getBoundingClientRect());
37
+ const graceArea = getHull([...paddedExitPoints, ...hoverTargetPoints]);
38
+ pointerGraceArea = graceArea;
39
+ isPointerInTransit.current = true;
40
+ }
41
+
42
+ watch(
43
+ [opts.triggerNode, opts.contentNode, opts.enabled],
44
+ ([triggerNode, contentNode, enabled]) => {
45
+ if (!triggerNode || !contentNode || !enabled) return;
46
+ const handleTriggerLeave = (e: PointerEvent) => {
47
+ handleCreateGraceArea(e, contentNode!);
48
+ };
49
+
50
+ const handleContentLeave = (e: PointerEvent) => {
51
+ handleCreateGraceArea(e, triggerNode!);
52
+ };
53
+
54
+ return executeCallbacks(
55
+ on(triggerNode, "pointerleave", handleTriggerLeave),
56
+ on(contentNode, "pointerleave", handleContentLeave)
57
+ );
58
+ }
59
+ );
60
+
61
+ watch(
62
+ () => pointerGraceArea,
63
+ () => {
64
+ const handleTrackPointerGrace = (e: PointerEvent) => {
65
+ if (!pointerGraceArea) return;
66
+ const target = e.target;
67
+ if (!isElement(target)) return;
68
+ const pointerPosition = { x: e.clientX, y: e.clientY };
69
+ const hasEnteredTarget =
70
+ opts.triggerNode()?.contains(target) || opts.contentNode()?.contains(target);
71
+ const isPointerOutsideGraceArea = !isPointInPolygon(
72
+ pointerPosition,
73
+ pointerGraceArea
74
+ );
75
+
76
+ if (hasEnteredTarget) {
77
+ handleRemoveGraceArea();
78
+ } else if (isPointerOutsideGraceArea) {
79
+ handleRemoveGraceArea();
80
+ opts.onPointerExit();
81
+ }
82
+ };
83
+
84
+ return on(document, "pointermove", handleTrackPointerGrace);
85
+ }
86
+ );
87
+
88
+ return {
89
+ isPointerInTransit,
90
+ };
91
+ }
92
+
93
+ type Point = { x: number; y: number };
94
+ type Polygon = Point[];
95
+
96
+ function getExitSideFromRect(point: Point, rect: DOMRect): Side {
97
+ const top = Math.abs(rect.top - point.y);
98
+ const bottom = Math.abs(rect.bottom - point.y);
99
+ const right = Math.abs(rect.right - point.x);
100
+ const left = Math.abs(rect.left - point.x);
101
+
102
+ switch (Math.min(top, bottom, right, left)) {
103
+ case left:
104
+ return "left";
105
+ case right:
106
+ return "right";
107
+ case top:
108
+ return "top";
109
+ case bottom:
110
+ return "bottom";
111
+ default:
112
+ throw new Error("unreachable");
113
+ }
114
+ }
115
+
116
+ function getPaddedExitPoints(exitPoint: Point, exitSide: Side, padding = 5) {
117
+ // we extend the tip of the exit point to make it easier to navigate without
118
+ // a minor jitter triggering a pointer exit
119
+ const tipPadding = padding * 1.5;
120
+ switch (exitSide) {
121
+ case "top":
122
+ return [
123
+ { x: exitPoint.x - padding, y: exitPoint.y + padding },
124
+ { x: exitPoint.x, y: exitPoint.y - tipPadding },
125
+ { x: exitPoint.x + padding, y: exitPoint.y + padding },
126
+ ];
127
+ case "bottom":
128
+ return [
129
+ { x: exitPoint.x - padding, y: exitPoint.y - padding },
130
+ { x: exitPoint.x, y: exitPoint.y + tipPadding },
131
+ { x: exitPoint.x + padding, y: exitPoint.y - padding },
132
+ ];
133
+ case "left":
134
+ return [
135
+ { x: exitPoint.x + padding, y: exitPoint.y - padding },
136
+ { x: exitPoint.x - tipPadding, y: exitPoint.y },
137
+ { x: exitPoint.x + padding, y: exitPoint.y + padding },
138
+ ];
139
+ case "right":
140
+ return [
141
+ { x: exitPoint.x - padding, y: exitPoint.y - padding },
142
+ { x: exitPoint.x + tipPadding, y: exitPoint.y },
143
+ { x: exitPoint.x - padding, y: exitPoint.y + padding },
144
+ ];
145
+ }
146
+ }
147
+
148
+ function getPointsFromRect(rect: DOMRect) {
149
+ const { top, right, bottom, left } = rect;
150
+ return [
151
+ { x: left, y: top },
152
+ { x: right, y: top },
153
+ { x: right, y: bottom },
154
+ { x: left, y: bottom },
155
+ ];
156
+ }
157
+
158
+ // Determine if a point is inside of a polygon.
159
+ // Based on https://github.com/substack/point-in-polygon
160
+ function isPointInPolygon(point: Point, polygon: Polygon) {
161
+ const { x, y } = point;
162
+ let inside = false;
163
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
164
+ const xi = polygon[i]!.x;
165
+ const yi = polygon[i]!.y;
166
+ const xj = polygon[j]!.x;
167
+ const yj = polygon[j]!.y;
168
+
169
+ // prettier-ignore
170
+ const intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi)
171
+ if (intersect) inside = !inside;
172
+ }
173
+
174
+ return inside;
175
+ }
176
+
177
+ // Returns a new array of points representing the convex hull of the given set of points.
178
+ // https://www.nayuki.io/page/convex-hull-algorithm
179
+ function getHull<P extends Point>(points: Readonly<Array<P>>): Array<P> {
180
+ const newPoints: Array<P> = points.slice();
181
+ newPoints.sort((a: Point, b: Point) => {
182
+ if (a.x < b.x) return -1;
183
+ else if (a.x > b.x) return +1;
184
+ else if (a.y < b.y) return -1;
185
+ else if (a.y > b.y) return +1;
186
+ else return 0;
187
+ });
188
+ return getHullPresorted(newPoints);
189
+ }
190
+
191
+ // Returns the convex hull, assuming that each points[i] <= points[i + 1]. Runs in O(n) time.
192
+ function getHullPresorted<P extends Point>(points: Readonly<Array<P>>): Array<P> {
193
+ if (points.length <= 1) return points.slice();
194
+
195
+ const upperHull: Array<P> = [];
196
+ for (let i = 0; i < points.length; i++) {
197
+ const p = points[i]!;
198
+ while (upperHull.length >= 2) {
199
+ const q = upperHull[upperHull.length - 1]!;
200
+ const r = upperHull[upperHull.length - 2]!;
201
+ if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) upperHull.pop();
202
+ else break;
203
+ }
204
+ upperHull.push(p);
205
+ }
206
+ upperHull.pop();
207
+
208
+ const lowerHull: Array<P> = [];
209
+ for (let i = points.length - 1; i >= 0; i--) {
210
+ const p = points[i]!;
211
+ while (lowerHull.length >= 2) {
212
+ const q = lowerHull[lowerHull.length - 1]!;
213
+ const r = lowerHull[lowerHull.length - 2]!;
214
+ if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) lowerHull.pop();
215
+ else break;
216
+ }
217
+ lowerHull.push(p);
218
+ }
219
+ lowerHull.pop();
220
+
221
+ if (
222
+ upperHull.length === 1 &&
223
+ lowerHull.length === 1 &&
224
+ upperHull[0]!.x === lowerHull[0]!.x &&
225
+ upperHull[0]!.y === lowerHull[0]!.y
226
+ )
227
+ return upperHull;
228
+ else return upperHull.concat(lowerHull);
229
+ }
@@ -0,0 +1,9 @@
1
+ globalThis.bitsIdCounter ??= { current: 0 };
2
+
3
+ /**
4
+ * Generates a unique ID based on a global counter.
5
+ */
6
+ export function useId(prefix = "bits") {
7
+ globalThis.bitsIdCounter.current++;
8
+ return `${prefix}-${globalThis.bitsIdCounter.current}`;
9
+ }
@@ -0,0 +1,19 @@
1
+ import type { Getter } from "svelte-toolbelt";
2
+
3
+ export function useResizeObserver(node: Getter<HTMLElement | null>, onResize: () => void) {
4
+ $effect(() => {
5
+ let rAF = 0;
6
+ const _node = node();
7
+ if (!_node) return;
8
+ const resizeObserver = new ResizeObserver(() => {
9
+ cancelAnimationFrame(rAF);
10
+ rAF = window.requestAnimationFrame(onResize);
11
+ });
12
+
13
+ resizeObserver.observe(_node);
14
+ return () => {
15
+ window.cancelAnimationFrame(rAF);
16
+ resizeObserver.unobserve(_node);
17
+ };
18
+ });
19
+ }
@@ -0,0 +1,141 @@
1
+ import { type ReadableBox, box } from "svelte-toolbelt";
2
+ import { getElemDirection } from "./locale.js";
3
+ import { getDirectionalKeys } from "./get-directional-keys.js";
4
+ import { kbd } from "./kbd.js";
5
+ import { isBrowser } from "./is.js";
6
+ import type { Orientation } from "$lib/shared/index.js";
7
+
8
+ type UseRovingFocusProps = {
9
+ /**
10
+ * The selector used to find the focusable candidates.
11
+ */
12
+ candidateAttr: string;
13
+
14
+ /**
15
+ * Custom candidate selector
16
+ */
17
+ candidateSelector?: string;
18
+
19
+ /**
20
+ * The id of the root node
21
+ */
22
+ rootNodeId: ReadableBox<string>;
23
+
24
+ /**
25
+ * Whether to loop through the candidates when reaching the end.
26
+ */
27
+ loop: ReadableBox<boolean>;
28
+
29
+ /**
30
+ * The orientation of the roving focus group. Used
31
+ * to determine how keyboard navigation should work.
32
+ */
33
+ orientation: ReadableBox<Orientation>;
34
+
35
+ /**
36
+ * A callback function called when a candidate is focused.
37
+ */
38
+ onCandidateFocus?: (node: HTMLElement) => void;
39
+ };
40
+
41
+ export type UseRovingFocusReturn = ReturnType<typeof useRovingFocus>;
42
+
43
+ export function useRovingFocus(props: UseRovingFocusProps) {
44
+ const currentTabStopId = box<string | null>(null);
45
+
46
+ function getCandidateNodes() {
47
+ if (!isBrowser) return [];
48
+ const node = document.getElementById(props.rootNodeId.current);
49
+ if (!node) return [];
50
+
51
+ if (props.candidateSelector) {
52
+ const candidates = Array.from(
53
+ node.querySelectorAll<HTMLElement>(props.candidateSelector)
54
+ );
55
+ return candidates;
56
+ } else {
57
+ const candidates = Array.from(
58
+ node.querySelectorAll<HTMLElement>(`[${props.candidateAttr}]:not([data-disabled])`)
59
+ );
60
+ return candidates;
61
+ }
62
+ }
63
+
64
+ function focusFirstCandidate() {
65
+ const items = getCandidateNodes();
66
+ if (!items.length) return;
67
+ items[0]?.focus();
68
+ }
69
+
70
+ function handleKeydown(
71
+ node: HTMLElement | null | undefined,
72
+ e: KeyboardEvent,
73
+ both: boolean = false
74
+ ) {
75
+ const rootNode = document.getElementById(props.rootNodeId.current);
76
+ if (!rootNode || !node) return;
77
+
78
+ const items = getCandidateNodes();
79
+ if (!items.length) return;
80
+
81
+ const currentIndex = items.indexOf(node);
82
+ const dir = getElemDirection(rootNode);
83
+ const { nextKey, prevKey } = getDirectionalKeys(dir, props.orientation.current);
84
+ const loop = props.loop.current;
85
+
86
+ const keyToIndex = {
87
+ [nextKey]: currentIndex + 1,
88
+ [prevKey]: currentIndex - 1,
89
+ [kbd.HOME]: 0,
90
+ [kbd.END]: items.length - 1,
91
+ };
92
+
93
+ if (both) {
94
+ const altNextKey = nextKey === kbd.ARROW_DOWN ? kbd.ARROW_RIGHT : kbd.ARROW_DOWN;
95
+ const altPrevKey = prevKey === kbd.ARROW_UP ? kbd.ARROW_LEFT : kbd.ARROW_UP;
96
+ keyToIndex[altNextKey] = currentIndex + 1;
97
+ keyToIndex[altPrevKey] = currentIndex - 1;
98
+ }
99
+
100
+ let itemIndex = keyToIndex[e.key];
101
+ if (itemIndex === undefined) return;
102
+ e.preventDefault();
103
+
104
+ if (itemIndex < 0 && loop) {
105
+ itemIndex = items.length - 1;
106
+ } else if (itemIndex === items.length && loop) {
107
+ itemIndex = 0;
108
+ }
109
+
110
+ const itemToFocus = items[itemIndex];
111
+ if (!itemToFocus) return;
112
+ itemToFocus.focus();
113
+ currentTabStopId.current = itemToFocus.id;
114
+ props.onCandidateFocus?.(itemToFocus);
115
+ return itemToFocus;
116
+ }
117
+
118
+ function getTabIndex(node: HTMLElement | null | undefined) {
119
+ const items = getCandidateNodes();
120
+ const anyActive = currentTabStopId.current !== null;
121
+
122
+ if (node && !anyActive && items[0] === node) {
123
+ currentTabStopId.current = node.id;
124
+ return 0;
125
+ } else if (node?.id === currentTabStopId.current) {
126
+ return 0;
127
+ }
128
+
129
+ return -1;
130
+ }
131
+
132
+ return {
133
+ setCurrentTabStopId(id: string) {
134
+ currentTabStopId.current = id;
135
+ },
136
+ getTabIndex,
137
+ handleKeydown,
138
+ focusFirstCandidate,
139
+ currentTabStopId,
140
+ };
141
+ }
@@ -0,0 +1,60 @@
1
+ /// <reference types="resize-observer-browser" />
2
+
3
+ import { untrack } from "svelte";
4
+ import { type WritableBox, afterTick } from "svelte-toolbelt";
5
+
6
+ export function useSize(node: WritableBox<HTMLElement | null>) {
7
+ let size = $state<{ width: number; height: number } | undefined>(undefined);
8
+
9
+ $effect(() => {
10
+ const currNode = node.current;
11
+ if (!currNode) {
12
+ size = undefined;
13
+ return;
14
+ }
15
+ afterTick(() => {
16
+ if (!currNode) return;
17
+ size = {
18
+ width: currNode.offsetWidth,
19
+ height: currNode.offsetHeight,
20
+ };
21
+ });
22
+
23
+ const resizeObserver = new ResizeObserver((entries) => {
24
+ if (!Array.isArray(entries) || !entries.length) return;
25
+
26
+ const entry = entries[0];
27
+ if (!entry) return;
28
+
29
+ let width: number;
30
+ let height: number;
31
+
32
+ if ("borderBoxSize" in entry) {
33
+ const borderSizeEntry = entry.borderBoxSize;
34
+ const borderSize = Array.isArray(borderSizeEntry)
35
+ ? borderSizeEntry[0]
36
+ : borderSizeEntry;
37
+ width = borderSize.inlineSize;
38
+ height = borderSize.blockSize;
39
+ } else {
40
+ width = currNode.offsetWidth;
41
+ height = currNode.offsetHeight;
42
+ }
43
+
44
+ untrack(() => (size = { width, height }));
45
+ });
46
+
47
+ resizeObserver.observe(currNode, { box: "border-box" });
48
+
49
+ return () => {
50
+ if (!currNode) return;
51
+ resizeObserver.unobserve(currNode);
52
+ };
53
+ });
54
+
55
+ return {
56
+ get value() {
57
+ return size;
58
+ },
59
+ };
60
+ }