tempest-react-sdk 0.25.0 → 0.26.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 (320) hide show
  1. package/README.md +14 -1
  2. package/bin/lib/alias/collect.mjs +94 -0
  3. package/bin/lib/alias/collect.test.mjs +95 -0
  4. package/bin/lib/alias/discover.mjs +77 -0
  5. package/bin/lib/alias/discover.test.mjs +189 -0
  6. package/bin/lib/alias/index.mjs +88 -0
  7. package/bin/lib/alias/index.test.mjs +138 -0
  8. package/bin/lib/alias/rewrite-css.mjs +76 -0
  9. package/bin/lib/alias/rewrite-css.test.mjs +85 -0
  10. package/bin/lib/alias/rewrite.mjs +141 -0
  11. package/bin/lib/alias/rewrite.test.mjs +148 -0
  12. package/bin/lib/alias/specifier.mjs +49 -0
  13. package/bin/lib/alias/specifier.test.mjs +85 -0
  14. package/bin/lib/alias/tsconfig.mjs +116 -0
  15. package/bin/lib/alias/typescript.mjs +23 -0
  16. package/bin/lib/icons/generate.mjs +156 -0
  17. package/bin/lib/icons/generate.test.mjs +125 -0
  18. package/bin/tempest.mjs +158 -13
  19. package/dist/audio/use-audio.cjs +1 -1
  20. package/dist/audio/use-audio.cjs.map +1 -1
  21. package/dist/audio/use-audio.js +12 -12
  22. package/dist/audio/use-audio.js.map +1 -1
  23. package/dist/charts/palette.cjs +1 -1
  24. package/dist/charts/palette.cjs.map +1 -1
  25. package/dist/charts/palette.js +2 -2
  26. package/dist/charts/palette.js.map +1 -1
  27. package/dist/charts.d.ts +5 -3
  28. package/dist/components/ClickOutside/ClickOutside.cjs +1 -1
  29. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  30. package/dist/components/ClickOutside/ClickOutside.js +3 -1
  31. package/dist/components/ClickOutside/ClickOutside.js.map +1 -1
  32. package/dist/components/DataTable/DataTable.cjs +1 -1
  33. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  34. package/dist/components/DataTable/DataTable.js +21 -23
  35. package/dist/components/DataTable/DataTable.js.map +1 -1
  36. package/dist/components/Kanban/Kanban.cjs +2 -0
  37. package/dist/components/Kanban/Kanban.cjs.map +1 -0
  38. package/dist/components/Kanban/Kanban.js +102 -0
  39. package/dist/components/Kanban/Kanban.js.map +1 -0
  40. package/dist/components/Kanban/Kanban.module.cjs +2 -0
  41. package/dist/components/Kanban/Kanban.module.cjs.map +1 -0
  42. package/dist/components/Kanban/Kanban.module.js +19 -0
  43. package/dist/components/Kanban/Kanban.module.js.map +1 -0
  44. package/dist/components/NotificationCenter/NotificationCenter.cjs +2 -0
  45. package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -0
  46. package/dist/components/NotificationCenter/NotificationCenter.js +83 -0
  47. package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -0
  48. package/dist/components/NotificationCenter/NotificationCenter.module.cjs +2 -0
  49. package/dist/components/NotificationCenter/NotificationCenter.module.cjs.map +1 -0
  50. package/dist/components/NotificationCenter/NotificationCenter.module.js +21 -0
  51. package/dist/components/NotificationCenter/NotificationCenter.module.js.map +1 -0
  52. package/dist/components/NotificationCenter/use-notification-inbox.cjs +2 -0
  53. package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -0
  54. package/dist/components/NotificationCenter/use-notification-inbox.js +63 -0
  55. package/dist/components/NotificationCenter/use-notification-inbox.js.map +1 -0
  56. package/dist/components/RefreshIndicator/RefreshIndicator.cjs +1 -1
  57. package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
  58. package/dist/components/RefreshIndicator/RefreshIndicator.js +17 -17
  59. package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
  60. package/dist/components/Tooltip/Tooltip.cjs +1 -1
  61. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  62. package/dist/components/Tooltip/Tooltip.js +26 -20
  63. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  64. package/dist/components/VirtualTable/VirtualTable.cjs +2 -0
  65. package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -0
  66. package/dist/components/VirtualTable/VirtualTable.js +116 -0
  67. package/dist/components/VirtualTable/VirtualTable.js.map +1 -0
  68. package/dist/components/VirtualTable/VirtualTable.module.cjs +2 -0
  69. package/dist/components/VirtualTable/VirtualTable.module.cjs.map +1 -0
  70. package/dist/components/VirtualTable/VirtualTable.module.js +20 -0
  71. package/dist/components/VirtualTable/VirtualTable.module.js.map +1 -0
  72. package/dist/components/Wizard/Wizard.cjs +1 -1
  73. package/dist/components/Wizard/Wizard.cjs.map +1 -1
  74. package/dist/components/Wizard/Wizard.js +53 -53
  75. package/dist/components/Wizard/Wizard.js.map +1 -1
  76. package/dist/geo/use-position-tracker.cjs +1 -1
  77. package/dist/geo/use-position-tracker.cjs.map +1 -1
  78. package/dist/geo/use-position-tracker.js +3 -1
  79. package/dist/geo/use-position-tracker.js.map +1 -1
  80. package/dist/hooks/use-async.cjs +1 -1
  81. package/dist/hooks/use-async.cjs.map +1 -1
  82. package/dist/hooks/use-async.js +3 -1
  83. package/dist/hooks/use-async.js.map +1 -1
  84. package/dist/hooks/use-click-outside.cjs +1 -1
  85. package/dist/hooks/use-click-outside.cjs.map +1 -1
  86. package/dist/hooks/use-click-outside.js +3 -1
  87. package/dist/hooks/use-click-outside.js.map +1 -1
  88. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  89. package/dist/hooks/use-deep-memo.js.map +1 -1
  90. package/dist/hooks/use-event-listener.cjs +1 -1
  91. package/dist/hooks/use-event-listener.cjs.map +1 -1
  92. package/dist/hooks/use-event-listener.js +3 -1
  93. package/dist/hooks/use-event-listener.js.map +1 -1
  94. package/dist/hooks/use-interval.cjs +1 -1
  95. package/dist/hooks/use-interval.cjs.map +1 -1
  96. package/dist/hooks/use-interval.js +3 -1
  97. package/dist/hooks/use-interval.js.map +1 -1
  98. package/dist/hooks/use-is-first-render.cjs.map +1 -1
  99. package/dist/hooks/use-is-first-render.js.map +1 -1
  100. package/dist/hooks/use-long-press-handlers.cjs +1 -1
  101. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  102. package/dist/hooks/use-long-press-handlers.js +25 -23
  103. package/dist/hooks/use-long-press-handlers.js.map +1 -1
  104. package/dist/hooks/use-long-press.cjs +1 -1
  105. package/dist/hooks/use-long-press.cjs.map +1 -1
  106. package/dist/hooks/use-long-press.js +3 -1
  107. package/dist/hooks/use-long-press.js.map +1 -1
  108. package/dist/hooks/use-online.cjs +1 -1
  109. package/dist/hooks/use-online.cjs.map +1 -1
  110. package/dist/hooks/use-online.js +6 -4
  111. package/dist/hooks/use-online.js.map +1 -1
  112. package/dist/hooks/use-previous.cjs.map +1 -1
  113. package/dist/hooks/use-previous.js.map +1 -1
  114. package/dist/hooks/use-service-worker-update.cjs +1 -1
  115. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  116. package/dist/hooks/use-service-worker-update.js +3 -1
  117. package/dist/hooks/use-service-worker-update.js.map +1 -1
  118. package/dist/hooks/use-sortable.cjs +2 -0
  119. package/dist/hooks/use-sortable.cjs.map +1 -0
  120. package/dist/hooks/use-sortable.js +169 -0
  121. package/dist/hooks/use-sortable.js.map +1 -0
  122. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  123. package/dist/hooks/use-stable-callback.js.map +1 -1
  124. package/dist/hooks/use-timeout.cjs +1 -1
  125. package/dist/hooks/use-timeout.cjs.map +1 -1
  126. package/dist/hooks/use-timeout.js +3 -1
  127. package/dist/hooks/use-timeout.js.map +1 -1
  128. package/dist/icons/Icon.cjs +2 -0
  129. package/dist/icons/Icon.cjs.map +1 -0
  130. package/dist/icons/Icon.js +24 -0
  131. package/dist/icons/Icon.js.map +1 -0
  132. package/dist/icons/IconProvider.cjs +2 -0
  133. package/dist/icons/IconProvider.cjs.map +1 -0
  134. package/dist/icons/IconProvider.js +24 -0
  135. package/dist/icons/IconProvider.js.map +1 -0
  136. package/dist/icons/generated/aliases.cjs +2 -0
  137. package/dist/icons/generated/aliases.cjs.map +1 -0
  138. package/dist/icons/generated/aliases.js +255 -0
  139. package/dist/icons/generated/aliases.js.map +1 -0
  140. package/dist/icons/generated/icon-names.cjs +2 -0
  141. package/dist/icons/generated/icon-names.cjs.map +1 -0
  142. package/dist/icons/generated/icon-names.js +6 -0
  143. package/dist/icons/generated/icon-names.js.map +1 -0
  144. package/dist/icons/generated/loaders.cjs +2 -0
  145. package/dist/icons/generated/loaders.cjs.map +1 -0
  146. package/dist/icons/generated/loaders.js +32 -0
  147. package/dist/icons/generated/loaders.js.map +1 -0
  148. package/dist/icons/generated/shard-a.cjs +2 -0
  149. package/dist/icons/generated/shard-a.cjs.map +1 -0
  150. package/dist/icons/generated/shard-a.js +114 -0
  151. package/dist/icons/generated/shard-a.js.map +1 -0
  152. package/dist/icons/generated/shard-b.cjs +2 -0
  153. package/dist/icons/generated/shard-b.cjs.map +1 -0
  154. package/dist/icons/generated/shard-b.js +156 -0
  155. package/dist/icons/generated/shard-b.js.map +1 -0
  156. package/dist/icons/generated/shard-c.cjs +2 -0
  157. package/dist/icons/generated/shard-c.cjs.map +1 -0
  158. package/dist/icons/generated/shard-c.js +269 -0
  159. package/dist/icons/generated/shard-c.js.map +1 -0
  160. package/dist/icons/generated/shard-d.cjs +2 -0
  161. package/dist/icons/generated/shard-d.cjs.map +1 -0
  162. package/dist/icons/generated/shard-d.js +62 -0
  163. package/dist/icons/generated/shard-d.js.map +1 -0
  164. package/dist/icons/generated/shard-e.cjs +2 -0
  165. package/dist/icons/generated/shard-e.cjs.map +1 -0
  166. package/dist/icons/generated/shard-e.js +32 -0
  167. package/dist/icons/generated/shard-e.js.map +1 -0
  168. package/dist/icons/generated/shard-f.cjs +2 -0
  169. package/dist/icons/generated/shard-f.cjs.map +1 -0
  170. package/dist/icons/generated/shard-f.js +139 -0
  171. package/dist/icons/generated/shard-f.js.map +1 -0
  172. package/dist/icons/generated/shard-g.cjs +2 -0
  173. package/dist/icons/generated/shard-g.cjs.map +1 -0
  174. package/dist/icons/generated/shard-g.js +61 -0
  175. package/dist/icons/generated/shard-g.js.map +1 -0
  176. package/dist/icons/generated/shard-h.cjs +2 -0
  177. package/dist/icons/generated/shard-h.cjs.map +1 -0
  178. package/dist/icons/generated/shard-h.js +63 -0
  179. package/dist/icons/generated/shard-h.js.map +1 -0
  180. package/dist/icons/generated/shard-i.cjs +2 -0
  181. package/dist/icons/generated/shard-i.cjs.map +1 -0
  182. package/dist/icons/generated/shard-i.js +30 -0
  183. package/dist/icons/generated/shard-i.js.map +1 -0
  184. package/dist/icons/generated/shard-j.cjs +2 -0
  185. package/dist/icons/generated/shard-j.cjs.map +1 -0
  186. package/dist/icons/generated/shard-j.js +10 -0
  187. package/dist/icons/generated/shard-j.js.map +1 -0
  188. package/dist/icons/generated/shard-k.cjs +2 -0
  189. package/dist/icons/generated/shard-k.cjs.map +1 -0
  190. package/dist/icons/generated/shard-k.js +16 -0
  191. package/dist/icons/generated/shard-k.js.map +1 -0
  192. package/dist/icons/generated/shard-l.cjs +2 -0
  193. package/dist/icons/generated/shard-l.cjs.map +1 -0
  194. package/dist/icons/generated/shard-l.js +88 -0
  195. package/dist/icons/generated/shard-l.js.map +1 -0
  196. package/dist/icons/generated/shard-m.cjs +2 -0
  197. package/dist/icons/generated/shard-m.cjs.map +1 -0
  198. package/dist/icons/generated/shard-m.js +140 -0
  199. package/dist/icons/generated/shard-m.js.map +1 -0
  200. package/dist/icons/generated/shard-n.cjs +2 -0
  201. package/dist/icons/generated/shard-n.cjs.map +1 -0
  202. package/dist/icons/generated/shard-n.js +24 -0
  203. package/dist/icons/generated/shard-n.js.map +1 -0
  204. package/dist/icons/generated/shard-o.cjs +2 -0
  205. package/dist/icons/generated/shard-o.cjs.map +1 -0
  206. package/dist/icons/generated/shard-o.js +17 -0
  207. package/dist/icons/generated/shard-o.js.map +1 -0
  208. package/dist/icons/generated/shard-p.cjs +2 -0
  209. package/dist/icons/generated/shard-p.cjs.map +1 -0
  210. package/dist/icons/generated/shard-p.js +115 -0
  211. package/dist/icons/generated/shard-p.js.map +1 -0
  212. package/dist/icons/generated/shard-q.cjs +2 -0
  213. package/dist/icons/generated/shard-q.cjs.map +1 -0
  214. package/dist/icons/generated/shard-q.js +10 -0
  215. package/dist/icons/generated/shard-q.js.map +1 -0
  216. package/dist/icons/generated/shard-r.cjs +2 -0
  217. package/dist/icons/generated/shard-r.cjs.map +1 -0
  218. package/dist/icons/generated/shard-r.js +77 -0
  219. package/dist/icons/generated/shard-r.js.map +1 -0
  220. package/dist/icons/generated/shard-s.cjs +2 -0
  221. package/dist/icons/generated/shard-s.cjs.map +1 -0
  222. package/dist/icons/generated/shard-s.js +255 -0
  223. package/dist/icons/generated/shard-s.js.map +1 -0
  224. package/dist/icons/generated/shard-t.cjs +2 -0
  225. package/dist/icons/generated/shard-t.cjs.map +1 -0
  226. package/dist/icons/generated/shard-t.js +109 -0
  227. package/dist/icons/generated/shard-t.js.map +1 -0
  228. package/dist/icons/generated/shard-u.cjs +2 -0
  229. package/dist/icons/generated/shard-u.cjs.map +1 -0
  230. package/dist/icons/generated/shard-u.js +49 -0
  231. package/dist/icons/generated/shard-u.js.map +1 -0
  232. package/dist/icons/generated/shard-v.cjs +2 -0
  233. package/dist/icons/generated/shard-v.cjs.map +1 -0
  234. package/dist/icons/generated/shard-v.js +30 -0
  235. package/dist/icons/generated/shard-v.js.map +1 -0
  236. package/dist/icons/generated/shard-w.cjs +2 -0
  237. package/dist/icons/generated/shard-w.cjs.map +1 -0
  238. package/dist/icons/generated/shard-w.js +48 -0
  239. package/dist/icons/generated/shard-w.js.map +1 -0
  240. package/dist/icons/generated/shard-x.cjs +2 -0
  241. package/dist/icons/generated/shard-x.cjs.map +1 -0
  242. package/dist/icons/generated/shard-x.js +10 -0
  243. package/dist/icons/generated/shard-x.js.map +1 -0
  244. package/dist/icons/generated/shard-z.cjs +2 -0
  245. package/dist/icons/generated/shard-z.cjs.map +1 -0
  246. package/dist/icons/generated/shard-z.js +25 -0
  247. package/dist/icons/generated/shard-z.js.map +1 -0
  248. package/dist/icons/icon-context.cjs +2 -0
  249. package/dist/icons/icon-context.cjs.map +1 -0
  250. package/dist/icons/icon-context.js +13 -0
  251. package/dist/icons/icon-context.js.map +1 -0
  252. package/dist/icons/is-icon-name.cjs +2 -0
  253. package/dist/icons/is-icon-name.cjs.map +1 -0
  254. package/dist/icons/is-icon-name.js +10 -0
  255. package/dist/icons/is-icon-name.js.map +1 -0
  256. package/dist/icons/shard-cache.cjs +2 -0
  257. package/dist/icons/shard-cache.cjs.map +1 -0
  258. package/dist/icons/shard-cache.js +41 -0
  259. package/dist/icons/shard-cache.js.map +1 -0
  260. package/dist/icons/use-icon.cjs +2 -0
  261. package/dist/icons/use-icon.cjs.map +1 -0
  262. package/dist/icons/use-icon.js +20 -0
  263. package/dist/icons/use-icon.js.map +1 -0
  264. package/dist/icons-virtual.d.ts +22 -0
  265. package/dist/icons.cjs +1 -0
  266. package/dist/icons.d.ts +220 -0
  267. package/dist/icons.js +9 -0
  268. package/dist/offline/use-offline-sync.cjs +1 -1
  269. package/dist/offline/use-offline-sync.cjs.map +1 -1
  270. package/dist/offline/use-offline-sync.js +3 -1
  271. package/dist/offline/use-offline-sync.js.map +1 -1
  272. package/dist/push/use-push-subscription.cjs +1 -1
  273. package/dist/push/use-push-subscription.cjs.map +1 -1
  274. package/dist/push/use-push-subscription.js +3 -1
  275. package/dist/push/use-push-subscription.js.map +1 -1
  276. package/dist/sse/use-event-stream.cjs +1 -1
  277. package/dist/sse/use-event-stream.cjs.map +1 -1
  278. package/dist/sse/use-event-stream.js +3 -1
  279. package/dist/sse/use-event-stream.js.map +1 -1
  280. package/dist/styles.css +1 -1
  281. package/dist/tempest-react-sdk.cjs +1 -1
  282. package/dist/tempest-react-sdk.d.ts +585 -3
  283. package/dist/tempest-react-sdk.js +189 -183
  284. package/dist/theme/ThemeProvider.cjs +1 -1
  285. package/dist/theme/ThemeProvider.cjs.map +1 -1
  286. package/dist/theme/ThemeProvider.js +6 -2
  287. package/dist/theme/ThemeProvider.js.map +1 -1
  288. package/dist/theme/color.cjs +1 -1
  289. package/dist/theme/color.cjs.map +1 -1
  290. package/dist/theme/color.js +77 -46
  291. package/dist/theme/color.js.map +1 -1
  292. package/dist/theme/create-theme.cjs +1 -1
  293. package/dist/theme/create-theme.cjs.map +1 -1
  294. package/dist/theme/create-theme.js +9 -3
  295. package/dist/theme/create-theme.js.map +1 -1
  296. package/dist/utils/compare-values.cjs +2 -0
  297. package/dist/utils/compare-values.cjs.map +1 -0
  298. package/dist/utils/compare-values.js +8 -0
  299. package/dist/utils/compare-values.js.map +1 -0
  300. package/dist/vision/use-camera-stream.cjs +1 -1
  301. package/dist/vision/use-camera-stream.cjs.map +1 -1
  302. package/dist/vision/use-camera-stream.js +3 -1
  303. package/dist/vision/use-camera-stream.js.map +1 -1
  304. package/dist/vite/create-vite-config.cjs +1 -1
  305. package/dist/vite/create-vite-config.cjs.map +1 -1
  306. package/dist/vite/create-vite-config.js +30 -22
  307. package/dist/vite/create-vite-config.js.map +1 -1
  308. package/dist/vite/tempest-icons.cjs +9 -0
  309. package/dist/vite/tempest-icons.cjs.map +1 -0
  310. package/dist/vite/tempest-icons.js +99 -0
  311. package/dist/vite/tempest-icons.js.map +1 -0
  312. package/dist/vite.cjs +1 -1
  313. package/dist/vite.d.ts +79 -0
  314. package/dist/vite.js +6 -5
  315. package/dist/ws/use-web-socket.cjs +1 -1
  316. package/dist/ws/use-web-socket.cjs.map +1 -1
  317. package/dist/ws/use-web-socket.js +3 -1
  318. package/dist/ws/use-web-socket.js.map +1 -1
  319. package/package.json +12 -3
  320. package/template/package.json +1 -1
@@ -1,33 +1,35 @@
1
- import { useCallback as e, useRef as t } from "react";
1
+ import { useCallback as e, useEffect as t, useRef as n } from "react";
2
2
  //#region src/hooks/use-long-press-handlers.ts
3
- function n(n, r = {}) {
4
- let { delayMs: i = 500, disabled: a = !1 } = r, o = t(null), s = t(!1), c = t(n);
5
- c.current = n;
6
- let l = e(() => {
7
- o.current !== null && (window.clearTimeout(o.current), o.current = null);
8
- }, []), u = e(() => {
9
- a || (s.current = !1, l(), o.current = window.setTimeout(() => {
10
- s.current = !0, c.current();
11
- }, i));
3
+ function r(r, i = {}) {
4
+ let { delayMs: a = 500, disabled: o = !1 } = i, s = n(null), c = n(!1), l = n(r);
5
+ t(() => {
6
+ l.current = r;
7
+ }, [r]);
8
+ let u = e(() => {
9
+ s.current !== null && (window.clearTimeout(s.current), s.current = null);
10
+ }, []), d = e(() => {
11
+ o || (c.current = !1, u(), s.current = window.setTimeout(() => {
12
+ c.current = !0, l.current();
13
+ }, a));
12
14
  }, [
13
- a,
14
- l,
15
- i
15
+ o,
16
+ u,
17
+ a
16
18
  ]);
17
19
  return {
18
- onMouseDown: u,
19
- onMouseUp: l,
20
- onMouseLeave: l,
21
- onTouchStart: u,
22
- onTouchEnd: l,
23
- onTouchMove: l,
20
+ onMouseDown: d,
21
+ onMouseUp: u,
22
+ onMouseLeave: u,
23
+ onTouchStart: d,
24
+ onTouchEnd: u,
25
+ onTouchMove: u,
24
26
  onContextMenu: e((e) => {
25
- a || (e.preventDefault(), s.current = !0, c.current());
26
- }, [a]),
27
- wasLongPress: () => s.current
27
+ o || (e.preventDefault(), c.current = !0, l.current());
28
+ }, [o]),
29
+ wasLongPress: () => c.current
28
30
  };
29
31
  }
30
32
  //#endregion
31
- export { n as useLongPressHandlers };
33
+ export { r as useLongPressHandlers };
32
34
 
33
35
  //# sourceMappingURL=use-long-press-handlers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-long-press-handlers.js","names":[],"sources":["../../src/hooks/use-long-press-handlers.ts"],"sourcesContent":["import { useCallback, useRef } from \"react\";\nimport type { MouseEvent as ReactMouseEvent, TouchEvent as ReactTouchEvent } from \"react\";\n\n/**\n * DOM event handlers produced by {@link useLongPressHandlers}, ready to spread\n * onto a JSX element (`<div {...handlers}>`).\n */\nexport interface LongPressHandlers {\n /** Starts the hold timer on mouse press. */\n onMouseDown: (event: ReactMouseEvent) => void;\n /** Cancels the pending hold when the mouse is released. */\n onMouseUp: () => void;\n /** Cancels the pending hold when the pointer leaves the element. */\n onMouseLeave: () => void;\n /** Starts the hold timer on touch start. */\n onTouchStart: (event: ReactTouchEvent) => void;\n /** Cancels the pending hold when the touch ends. */\n onTouchEnd: () => void;\n /** Cancels the pending hold when the finger moves. */\n onTouchMove: () => void;\n /** Fires the long-press immediately (desktop right-click parity). */\n onContextMenu: (event: ReactMouseEvent) => void;\n}\n\n/** Options accepted by {@link useLongPressHandlers}. */\nexport interface UseLongPressHandlersOptions {\n /** Hold duration in ms before `onLongPress` fires. Defaults to `500`. */\n delayMs?: number;\n /** When `true`, the hook is inert and every handler is a no-op. */\n disabled?: boolean;\n}\n\n/** Return shape of {@link useLongPressHandlers}. */\nexport type UseLongPressHandlersResult = LongPressHandlers & {\n /**\n * Reads whether the most recent interaction fired a long-press. Use it in\n * the element's `onClick` to suppress the click that follows a long-press.\n */\n wasLongPress: () => boolean;\n};\n\n/**\n * Returns DOM event handlers that detect a long press (touch or mouse hold)\n * and invoke `onLongPress` once after `delayMs`.\n *\n * Cancels on touch movement or pointer release. Also wires `contextmenu` to\n * fire `onLongPress` immediately so a right-click on desktop opens selection\n * mode the same way an Android long-press does on mobile.\n *\n * The hook does not `preventDefault` on the underlying click — the consumer\n * decides whether the subsequent click should still fire. Track that with the\n * returned `wasLongPress()` guard to tell \"long-press fired\" apart from a\n * \"regular click\".\n *\n * Unlike {@link useLongPress}, which attaches pointer listeners to a `ref`,\n * this variant returns handler props you spread directly onto an element and\n * exposes a `wasLongPress()` guard.\n *\n * @param onLongPress - Callback invoked once the hold threshold is reached.\n * @param options - Optional `delayMs` and `disabled` flags.\n * @returns The spreadable handlers plus a `wasLongPress()` guard.\n *\n * @example\n * const longPress = useLongPressHandlers(() => enterSelectionMode(), { delayMs: 600 });\n * <button {...longPress} onClick={() => { if (!longPress.wasLongPress()) navigate(); }}>\n * Item\n * </button>\n */\nexport function useLongPressHandlers(\n onLongPress: () => void,\n options: UseLongPressHandlersOptions = {},\n): UseLongPressHandlersResult {\n const { delayMs = 500, disabled = false } = options;\n const timerRef = useRef<number | null>(null);\n const firedRef = useRef<boolean>(false);\n const callbackRef = useRef<() => void>(onLongPress);\n callbackRef.current = onLongPress;\n\n const clear = useCallback((): void => {\n if (timerRef.current !== null) {\n window.clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n const start = useCallback((): void => {\n if (disabled) return;\n firedRef.current = false;\n clear();\n timerRef.current = window.setTimeout(() => {\n firedRef.current = true;\n callbackRef.current();\n }, delayMs);\n }, [disabled, clear, delayMs]);\n\n const onContextMenu = useCallback(\n (event: ReactMouseEvent): void => {\n if (disabled) return;\n event.preventDefault();\n firedRef.current = true;\n callbackRef.current();\n },\n [disabled],\n );\n\n return {\n onMouseDown: start,\n onMouseUp: clear,\n onMouseLeave: clear,\n onTouchStart: start,\n onTouchEnd: clear,\n onTouchMove: clear,\n onContextMenu,\n wasLongPress: () => firedRef.current,\n };\n}\n"],"mappings":";;AAoEA,SAAgB,EACZ,GACA,IAAuC,CAAC,GACd;CAC1B,IAAM,EAAE,aAAU,KAAK,cAAW,OAAU,GACtC,IAAW,EAAsB,IAAI,GACrC,IAAW,EAAgB,EAAK,GAChC,IAAc,EAAmB,CAAW;CAClD,EAAY,UAAU;CAEtB,IAAM,IAAQ,QAAwB;EAClC,AAAI,EAAS,YAAY,SACrB,OAAO,aAAa,EAAS,OAAO,GACpC,EAAS,UAAU;CAE3B,GAAG,CAAC,CAAC,GAEC,IAAQ,QAAwB;EAC9B,MACJ,EAAS,UAAU,IACnB,EAAM,GACN,EAAS,UAAU,OAAO,iBAAiB;GAEvC,AADA,EAAS,UAAU,IACnB,EAAY,QAAQ;EACxB,GAAG,CAAO;CACd,GAAG;EAAC;EAAU;EAAO;CAAO,CAAC;CAY7B,OAAO;EACH,aAAa;EACb,WAAW;EACX,cAAc;EACd,cAAc;EACd,YAAY;EACZ,aAAa;EACb,eAjBkB,GACjB,MAAiC;GAC1B,MACJ,EAAM,eAAe,GACrB,EAAS,UAAU,IACnB,EAAY,QAAQ;EACxB,GACA,CAAC,CAAQ,CAUT;EACA,oBAAoB,EAAS;CACjC;AACJ"}
1
+ {"version":3,"file":"use-long-press-handlers.js","names":[],"sources":["../../src/hooks/use-long-press-handlers.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport type { MouseEvent as ReactMouseEvent, TouchEvent as ReactTouchEvent } from \"react\";\n\n/**\n * DOM event handlers produced by {@link useLongPressHandlers}, ready to spread\n * onto a JSX element (`<div {...handlers}>`).\n */\nexport interface LongPressHandlers {\n /** Starts the hold timer on mouse press. */\n onMouseDown: (event: ReactMouseEvent) => void;\n /** Cancels the pending hold when the mouse is released. */\n onMouseUp: () => void;\n /** Cancels the pending hold when the pointer leaves the element. */\n onMouseLeave: () => void;\n /** Starts the hold timer on touch start. */\n onTouchStart: (event: ReactTouchEvent) => void;\n /** Cancels the pending hold when the touch ends. */\n onTouchEnd: () => void;\n /** Cancels the pending hold when the finger moves. */\n onTouchMove: () => void;\n /** Fires the long-press immediately (desktop right-click parity). */\n onContextMenu: (event: ReactMouseEvent) => void;\n}\n\n/** Options accepted by {@link useLongPressHandlers}. */\nexport interface UseLongPressHandlersOptions {\n /** Hold duration in ms before `onLongPress` fires. Defaults to `500`. */\n delayMs?: number;\n /** When `true`, the hook is inert and every handler is a no-op. */\n disabled?: boolean;\n}\n\n/** Return shape of {@link useLongPressHandlers}. */\nexport type UseLongPressHandlersResult = LongPressHandlers & {\n /**\n * Reads whether the most recent interaction fired a long-press. Use it in\n * the element's `onClick` to suppress the click that follows a long-press.\n */\n wasLongPress: () => boolean;\n};\n\n/**\n * Returns DOM event handlers that detect a long press (touch or mouse hold)\n * and invoke `onLongPress` once after `delayMs`.\n *\n * Cancels on touch movement or pointer release. Also wires `contextmenu` to\n * fire `onLongPress` immediately so a right-click on desktop opens selection\n * mode the same way an Android long-press does on mobile.\n *\n * The hook does not `preventDefault` on the underlying click — the consumer\n * decides whether the subsequent click should still fire. Track that with the\n * returned `wasLongPress()` guard to tell \"long-press fired\" apart from a\n * \"regular click\".\n *\n * Unlike {@link useLongPress}, which attaches pointer listeners to a `ref`,\n * this variant returns handler props you spread directly onto an element and\n * exposes a `wasLongPress()` guard.\n *\n * @param onLongPress - Callback invoked once the hold threshold is reached.\n * @param options - Optional `delayMs` and `disabled` flags.\n * @returns The spreadable handlers plus a `wasLongPress()` guard.\n *\n * @example\n * const longPress = useLongPressHandlers(() => enterSelectionMode(), { delayMs: 600 });\n * <button {...longPress} onClick={() => { if (!longPress.wasLongPress()) navigate(); }}>\n * Item\n * </button>\n */\nexport function useLongPressHandlers(\n onLongPress: () => void,\n options: UseLongPressHandlersOptions = {},\n): UseLongPressHandlersResult {\n const { delayMs = 500, disabled = false } = options;\n const timerRef = useRef<number | null>(null);\n const firedRef = useRef<boolean>(false);\n const callbackRef = useRef<() => void>(onLongPress);\n useEffect(() => {\n callbackRef.current = onLongPress;\n }, [onLongPress]);\n\n const clear = useCallback((): void => {\n if (timerRef.current !== null) {\n window.clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n const start = useCallback((): void => {\n if (disabled) return;\n firedRef.current = false;\n clear();\n timerRef.current = window.setTimeout(() => {\n firedRef.current = true;\n callbackRef.current();\n }, delayMs);\n }, [disabled, clear, delayMs]);\n\n const onContextMenu = useCallback(\n (event: ReactMouseEvent): void => {\n if (disabled) return;\n event.preventDefault();\n firedRef.current = true;\n callbackRef.current();\n },\n [disabled],\n );\n\n return {\n onMouseDown: start,\n onMouseUp: clear,\n onMouseLeave: clear,\n onTouchStart: start,\n onTouchEnd: clear,\n onTouchMove: clear,\n onContextMenu,\n wasLongPress: () => firedRef.current,\n };\n}\n"],"mappings":";;AAoEA,SAAgB,EACZ,GACA,IAAuC,CAAC,GACd;CAC1B,IAAM,EAAE,aAAU,KAAK,cAAW,OAAU,GACtC,IAAW,EAAsB,IAAI,GACrC,IAAW,EAAgB,EAAK,GAChC,IAAc,EAAmB,CAAW;CAClD,QAAgB;EACZ,EAAY,UAAU;CAC1B,GAAG,CAAC,CAAW,CAAC;CAEhB,IAAM,IAAQ,QAAwB;EAClC,AAAI,EAAS,YAAY,SACrB,OAAO,aAAa,EAAS,OAAO,GACpC,EAAS,UAAU;CAE3B,GAAG,CAAC,CAAC,GAEC,IAAQ,QAAwB;EAC9B,MACJ,EAAS,UAAU,IACnB,EAAM,GACN,EAAS,UAAU,OAAO,iBAAiB;GAEvC,AADA,EAAS,UAAU,IACnB,EAAY,QAAQ;EACxB,GAAG,CAAO;CACd,GAAG;EAAC;EAAU;EAAO;CAAO,CAAC;CAY7B,OAAO;EACH,aAAa;EACb,WAAW;EACX,cAAc;EACd,cAAc;EACd,YAAY;EACZ,aAAa;EACb,eAjBkB,GACjB,MAAiC;GAC1B,MACJ,EAAM,eAAe,GACrB,EAAS,UAAU,IACnB,EAAY,QAAQ;EACxB,GACA,CAAC,CAAQ,CAUT;EACA,oBAAoB,EAAS;CACjC;AACJ"}
@@ -1,2 +1,2 @@
1
- let e=require("react");function t(t,n,r={}){let{delay:i=500,moveThreshold:a=10}=r,o=(0,e.useRef)(n);o.current=n,(0,e.useEffect)(()=>{let e=t.current;if(!e)return;let n=null,r=0,s=0,c=()=>{n&&=(clearTimeout(n),null)},l=e=>{r=e.clientX,s=e.clientY,c(),n=setTimeout(()=>{n=null,o.current()},i)},u=e=>{if(n===null)return;let t=e.clientX-r,i=e.clientY-s;Math.hypot(t,i)>a&&c()};return e.addEventListener(`pointerdown`,l),e.addEventListener(`pointermove`,u),e.addEventListener(`pointerup`,c),e.addEventListener(`pointercancel`,c),e.addEventListener(`pointerleave`,c),()=>{c(),e.removeEventListener(`pointerdown`,l),e.removeEventListener(`pointermove`,u),e.removeEventListener(`pointerup`,c),e.removeEventListener(`pointercancel`,c),e.removeEventListener(`pointerleave`,c)}},[t,i,a])}exports.useLongPress=t;
1
+ let e=require("react");function t(t,n,r={}){let{delay:i=500,moveThreshold:a=10}=r,o=(0,e.useRef)(n);(0,e.useEffect)(()=>{o.current=n},[n]),(0,e.useEffect)(()=>{let e=t.current;if(!e)return;let n=null,r=0,s=0,c=()=>{n&&=(clearTimeout(n),null)},l=e=>{r=e.clientX,s=e.clientY,c(),n=setTimeout(()=>{n=null,o.current()},i)},u=e=>{if(n===null)return;let t=e.clientX-r,i=e.clientY-s;Math.hypot(t,i)>a&&c()};return e.addEventListener(`pointerdown`,l),e.addEventListener(`pointermove`,u),e.addEventListener(`pointerup`,c),e.addEventListener(`pointercancel`,c),e.addEventListener(`pointerleave`,c),()=>{c(),e.removeEventListener(`pointerdown`,l),e.removeEventListener(`pointermove`,u),e.removeEventListener(`pointerup`,c),e.removeEventListener(`pointercancel`,c),e.removeEventListener(`pointerleave`,c)}},[t,i,a])}exports.useLongPress=t;
2
2
  //# sourceMappingURL=use-long-press.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-long-press.cjs","names":[],"sources":["../../src/hooks/use-long-press.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport interface UseLongPressOptions {\n /** Press duration in ms. Default `500`. */\n delay?: number;\n /** Pixel threshold — finger/mouse movement beyond this cancels the press. Default `10`. */\n moveThreshold?: number;\n}\n\n/**\n * Detect long-press / long-tap gestures. Fires `fn` after `delay` ms\n * while the element is held. Cancels on move beyond `moveThreshold` or\n * pointer up before `delay`.\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null);\n * useLongPress(ref, () => openContextMenu(), { delay: 600 });\n */\nexport function useLongPress<T extends HTMLElement>(\n ref: RefObject<T | null>,\n fn: () => void,\n options: UseLongPressOptions = {},\n): void {\n const { delay = 500, moveThreshold = 10 } = options;\n const fnRef = useRef(fn);\n fnRef.current = fn;\n\n useEffect(() => {\n const node = ref.current;\n if (!node) return;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let startX = 0;\n let startY = 0;\n\n const cancel = (): void => {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n };\n\n const onDown = (event: PointerEvent): void => {\n startX = event.clientX;\n startY = event.clientY;\n cancel();\n timer = setTimeout(() => {\n timer = null;\n fnRef.current();\n }, delay);\n };\n\n const onMove = (event: PointerEvent): void => {\n if (timer === null) return;\n const dx = event.clientX - startX;\n const dy = event.clientY - startY;\n if (Math.hypot(dx, dy) > moveThreshold) cancel();\n };\n\n node.addEventListener(\"pointerdown\", onDown);\n node.addEventListener(\"pointermove\", onMove);\n node.addEventListener(\"pointerup\", cancel);\n node.addEventListener(\"pointercancel\", cancel);\n node.addEventListener(\"pointerleave\", cancel);\n return () => {\n cancel();\n node.removeEventListener(\"pointerdown\", onDown);\n node.removeEventListener(\"pointermove\", onMove);\n node.removeEventListener(\"pointerup\", cancel);\n node.removeEventListener(\"pointercancel\", cancel);\n node.removeEventListener(\"pointerleave\", cancel);\n };\n }, [ref, delay, moveThreshold]);\n}\n"],"mappings":"uBAmBA,SAAgB,EACZ,EACA,EACA,EAA+B,CAAC,EAC5B,CACJ,GAAM,CAAE,QAAQ,IAAK,gBAAgB,IAAO,EACtC,GAAA,EAAA,EAAA,OAAA,CAAe,CAAE,EACvB,EAAM,QAAU,GAEhB,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAM,EAAO,EAAI,QACjB,GAAI,CAAC,EAAM,OACX,IAAI,EAA8C,KAC9C,EAAS,EACT,EAAS,EAEP,MAAqB,CACvB,AAEI,KADA,aAAa,CAAK,EACV,KAEhB,EAEM,EAAU,GAA8B,CAC1C,EAAS,EAAM,QACf,EAAS,EAAM,QACf,EAAO,EACP,EAAQ,eAAiB,CACrB,EAAQ,KACR,EAAM,QAAQ,CAClB,EAAG,CAAK,CACZ,EAEM,EAAU,GAA8B,CAC1C,GAAI,IAAU,KAAM,OACpB,IAAM,EAAK,EAAM,QAAU,EACrB,EAAK,EAAM,QAAU,EACvB,KAAK,MAAM,EAAI,CAAE,EAAI,GAAe,EAAO,CACnD,EAOA,OALA,EAAK,iBAAiB,cAAe,CAAM,EAC3C,EAAK,iBAAiB,cAAe,CAAM,EAC3C,EAAK,iBAAiB,YAAa,CAAM,EACzC,EAAK,iBAAiB,gBAAiB,CAAM,EAC7C,EAAK,iBAAiB,eAAgB,CAAM,MAC/B,CACT,EAAO,EACP,EAAK,oBAAoB,cAAe,CAAM,EAC9C,EAAK,oBAAoB,cAAe,CAAM,EAC9C,EAAK,oBAAoB,YAAa,CAAM,EAC5C,EAAK,oBAAoB,gBAAiB,CAAM,EAChD,EAAK,oBAAoB,eAAgB,CAAM,CACnD,CACJ,EAAG,CAAC,EAAK,EAAO,CAAa,CAAC,CAClC"}
1
+ {"version":3,"file":"use-long-press.cjs","names":[],"sources":["../../src/hooks/use-long-press.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport interface UseLongPressOptions {\n /** Press duration in ms. Default `500`. */\n delay?: number;\n /** Pixel threshold — finger/mouse movement beyond this cancels the press. Default `10`. */\n moveThreshold?: number;\n}\n\n/**\n * Detect long-press / long-tap gestures. Fires `fn` after `delay` ms\n * while the element is held. Cancels on move beyond `moveThreshold` or\n * pointer up before `delay`.\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null);\n * useLongPress(ref, () => openContextMenu(), { delay: 600 });\n */\nexport function useLongPress<T extends HTMLElement>(\n ref: RefObject<T | null>,\n fn: () => void,\n options: UseLongPressOptions = {},\n): void {\n const { delay = 500, moveThreshold = 10 } = options;\n const fnRef = useRef(fn);\n useEffect(() => {\n fnRef.current = fn;\n }, [fn]);\n\n useEffect(() => {\n const node = ref.current;\n if (!node) return;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let startX = 0;\n let startY = 0;\n\n const cancel = (): void => {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n };\n\n const onDown = (event: PointerEvent): void => {\n startX = event.clientX;\n startY = event.clientY;\n cancel();\n timer = setTimeout(() => {\n timer = null;\n fnRef.current();\n }, delay);\n };\n\n const onMove = (event: PointerEvent): void => {\n if (timer === null) return;\n const dx = event.clientX - startX;\n const dy = event.clientY - startY;\n if (Math.hypot(dx, dy) > moveThreshold) cancel();\n };\n\n node.addEventListener(\"pointerdown\", onDown);\n node.addEventListener(\"pointermove\", onMove);\n node.addEventListener(\"pointerup\", cancel);\n node.addEventListener(\"pointercancel\", cancel);\n node.addEventListener(\"pointerleave\", cancel);\n return () => {\n cancel();\n node.removeEventListener(\"pointerdown\", onDown);\n node.removeEventListener(\"pointermove\", onMove);\n node.removeEventListener(\"pointerup\", cancel);\n node.removeEventListener(\"pointercancel\", cancel);\n node.removeEventListener(\"pointerleave\", cancel);\n };\n }, [ref, delay, moveThreshold]);\n}\n"],"mappings":"uBAmBA,SAAgB,EACZ,EACA,EACA,EAA+B,CAAC,EAC5B,CACJ,GAAM,CAAE,QAAQ,IAAK,gBAAgB,IAAO,EACtC,GAAA,EAAA,EAAA,OAAA,CAAe,CAAE,GACvB,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAM,QAAU,CACpB,EAAG,CAAC,CAAE,CAAC,GAEP,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAM,EAAO,EAAI,QACjB,GAAI,CAAC,EAAM,OACX,IAAI,EAA8C,KAC9C,EAAS,EACT,EAAS,EAEP,MAAqB,CACvB,AAEI,KADA,aAAa,CAAK,EACV,KAEhB,EAEM,EAAU,GAA8B,CAC1C,EAAS,EAAM,QACf,EAAS,EAAM,QACf,EAAO,EACP,EAAQ,eAAiB,CACrB,EAAQ,KACR,EAAM,QAAQ,CAClB,EAAG,CAAK,CACZ,EAEM,EAAU,GAA8B,CAC1C,GAAI,IAAU,KAAM,OACpB,IAAM,EAAK,EAAM,QAAU,EACrB,EAAK,EAAM,QAAU,EACvB,KAAK,MAAM,EAAI,CAAE,EAAI,GAAe,EAAO,CACnD,EAOA,OALA,EAAK,iBAAiB,cAAe,CAAM,EAC3C,EAAK,iBAAiB,cAAe,CAAM,EAC3C,EAAK,iBAAiB,YAAa,CAAM,EACzC,EAAK,iBAAiB,gBAAiB,CAAM,EAC7C,EAAK,iBAAiB,eAAgB,CAAM,MAC/B,CACT,EAAO,EACP,EAAK,oBAAoB,cAAe,CAAM,EAC9C,EAAK,oBAAoB,cAAe,CAAM,EAC9C,EAAK,oBAAoB,YAAa,CAAM,EAC5C,EAAK,oBAAoB,gBAAiB,CAAM,EAChD,EAAK,oBAAoB,eAAgB,CAAM,CACnD,CACJ,EAAG,CAAC,EAAK,EAAO,CAAa,CAAC,CAClC"}
@@ -2,7 +2,9 @@ import { useEffect as e, useRef as t } from "react";
2
2
  //#region src/hooks/use-long-press.ts
3
3
  function n(n, r, i = {}) {
4
4
  let { delay: a = 500, moveThreshold: o = 10 } = i, s = t(r);
5
- s.current = r, e(() => {
5
+ e(() => {
6
+ s.current = r;
7
+ }, [r]), e(() => {
6
8
  let e = n.current;
7
9
  if (!e) return;
8
10
  let t = null, r = 0, i = 0, c = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"use-long-press.js","names":[],"sources":["../../src/hooks/use-long-press.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport interface UseLongPressOptions {\n /** Press duration in ms. Default `500`. */\n delay?: number;\n /** Pixel threshold — finger/mouse movement beyond this cancels the press. Default `10`. */\n moveThreshold?: number;\n}\n\n/**\n * Detect long-press / long-tap gestures. Fires `fn` after `delay` ms\n * while the element is held. Cancels on move beyond `moveThreshold` or\n * pointer up before `delay`.\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null);\n * useLongPress(ref, () => openContextMenu(), { delay: 600 });\n */\nexport function useLongPress<T extends HTMLElement>(\n ref: RefObject<T | null>,\n fn: () => void,\n options: UseLongPressOptions = {},\n): void {\n const { delay = 500, moveThreshold = 10 } = options;\n const fnRef = useRef(fn);\n fnRef.current = fn;\n\n useEffect(() => {\n const node = ref.current;\n if (!node) return;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let startX = 0;\n let startY = 0;\n\n const cancel = (): void => {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n };\n\n const onDown = (event: PointerEvent): void => {\n startX = event.clientX;\n startY = event.clientY;\n cancel();\n timer = setTimeout(() => {\n timer = null;\n fnRef.current();\n }, delay);\n };\n\n const onMove = (event: PointerEvent): void => {\n if (timer === null) return;\n const dx = event.clientX - startX;\n const dy = event.clientY - startY;\n if (Math.hypot(dx, dy) > moveThreshold) cancel();\n };\n\n node.addEventListener(\"pointerdown\", onDown);\n node.addEventListener(\"pointermove\", onMove);\n node.addEventListener(\"pointerup\", cancel);\n node.addEventListener(\"pointercancel\", cancel);\n node.addEventListener(\"pointerleave\", cancel);\n return () => {\n cancel();\n node.removeEventListener(\"pointerdown\", onDown);\n node.removeEventListener(\"pointermove\", onMove);\n node.removeEventListener(\"pointerup\", cancel);\n node.removeEventListener(\"pointercancel\", cancel);\n node.removeEventListener(\"pointerleave\", cancel);\n };\n }, [ref, delay, moveThreshold]);\n}\n"],"mappings":";;AAmBA,SAAgB,EACZ,GACA,GACA,IAA+B,CAAC,GAC5B;CACJ,IAAM,EAAE,WAAQ,KAAK,mBAAgB,OAAO,GACtC,IAAQ,EAAO,CAAE;CAGvB,AAFA,EAAM,UAAU,GAEhB,QAAgB;EACZ,IAAM,IAAO,EAAI;EACjB,IAAI,CAAC,GAAM;EACX,IAAI,IAA8C,MAC9C,IAAS,GACT,IAAS,GAEP,UAAqB;GACvB,AAEI,OADA,aAAa,CAAK,GACV;EAEhB,GAEM,KAAU,MAA8B;GAI1C,AAHA,IAAS,EAAM,SACf,IAAS,EAAM,SACf,EAAO,GACP,IAAQ,iBAAiB;IAErB,AADA,IAAQ,MACR,EAAM,QAAQ;GAClB,GAAG,CAAK;EACZ,GAEM,KAAU,MAA8B;GAC1C,IAAI,MAAU,MAAM;GACpB,IAAM,IAAK,EAAM,UAAU,GACrB,IAAK,EAAM,UAAU;GAC3B,AAAI,KAAK,MAAM,GAAI,CAAE,IAAI,KAAe,EAAO;EACnD;EAOA,OALA,EAAK,iBAAiB,eAAe,CAAM,GAC3C,EAAK,iBAAiB,eAAe,CAAM,GAC3C,EAAK,iBAAiB,aAAa,CAAM,GACzC,EAAK,iBAAiB,iBAAiB,CAAM,GAC7C,EAAK,iBAAiB,gBAAgB,CAAM,SAC/B;GAMT,AALA,EAAO,GACP,EAAK,oBAAoB,eAAe,CAAM,GAC9C,EAAK,oBAAoB,eAAe,CAAM,GAC9C,EAAK,oBAAoB,aAAa,CAAM,GAC5C,EAAK,oBAAoB,iBAAiB,CAAM,GAChD,EAAK,oBAAoB,gBAAgB,CAAM;EACnD;CACJ,GAAG;EAAC;EAAK;EAAO;CAAa,CAAC;AAClC"}
1
+ {"version":3,"file":"use-long-press.js","names":[],"sources":["../../src/hooks/use-long-press.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport interface UseLongPressOptions {\n /** Press duration in ms. Default `500`. */\n delay?: number;\n /** Pixel threshold — finger/mouse movement beyond this cancels the press. Default `10`. */\n moveThreshold?: number;\n}\n\n/**\n * Detect long-press / long-tap gestures. Fires `fn` after `delay` ms\n * while the element is held. Cancels on move beyond `moveThreshold` or\n * pointer up before `delay`.\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null);\n * useLongPress(ref, () => openContextMenu(), { delay: 600 });\n */\nexport function useLongPress<T extends HTMLElement>(\n ref: RefObject<T | null>,\n fn: () => void,\n options: UseLongPressOptions = {},\n): void {\n const { delay = 500, moveThreshold = 10 } = options;\n const fnRef = useRef(fn);\n useEffect(() => {\n fnRef.current = fn;\n }, [fn]);\n\n useEffect(() => {\n const node = ref.current;\n if (!node) return;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let startX = 0;\n let startY = 0;\n\n const cancel = (): void => {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n };\n\n const onDown = (event: PointerEvent): void => {\n startX = event.clientX;\n startY = event.clientY;\n cancel();\n timer = setTimeout(() => {\n timer = null;\n fnRef.current();\n }, delay);\n };\n\n const onMove = (event: PointerEvent): void => {\n if (timer === null) return;\n const dx = event.clientX - startX;\n const dy = event.clientY - startY;\n if (Math.hypot(dx, dy) > moveThreshold) cancel();\n };\n\n node.addEventListener(\"pointerdown\", onDown);\n node.addEventListener(\"pointermove\", onMove);\n node.addEventListener(\"pointerup\", cancel);\n node.addEventListener(\"pointercancel\", cancel);\n node.addEventListener(\"pointerleave\", cancel);\n return () => {\n cancel();\n node.removeEventListener(\"pointerdown\", onDown);\n node.removeEventListener(\"pointermove\", onMove);\n node.removeEventListener(\"pointerup\", cancel);\n node.removeEventListener(\"pointercancel\", cancel);\n node.removeEventListener(\"pointerleave\", cancel);\n };\n }, [ref, delay, moveThreshold]);\n}\n"],"mappings":";;AAmBA,SAAgB,EACZ,GACA,GACA,IAA+B,CAAC,GAC5B;CACJ,IAAM,EAAE,WAAQ,KAAK,mBAAgB,OAAO,GACtC,IAAQ,EAAO,CAAE;CAKvB,AAJA,QAAgB;EACZ,EAAM,UAAU;CACpB,GAAG,CAAC,CAAE,CAAC,GAEP,QAAgB;EACZ,IAAM,IAAO,EAAI;EACjB,IAAI,CAAC,GAAM;EACX,IAAI,IAA8C,MAC9C,IAAS,GACT,IAAS,GAEP,UAAqB;GACvB,AAEI,OADA,aAAa,CAAK,GACV;EAEhB,GAEM,KAAU,MAA8B;GAI1C,AAHA,IAAS,EAAM,SACf,IAAS,EAAM,SACf,EAAO,GACP,IAAQ,iBAAiB;IAErB,AADA,IAAQ,MACR,EAAM,QAAQ;GAClB,GAAG,CAAK;EACZ,GAEM,KAAU,MAA8B;GAC1C,IAAI,MAAU,MAAM;GACpB,IAAM,IAAK,EAAM,UAAU,GACrB,IAAK,EAAM,UAAU;GAC3B,AAAI,KAAK,MAAM,GAAI,CAAE,IAAI,KAAe,EAAO;EACnD;EAOA,OALA,EAAK,iBAAiB,eAAe,CAAM,GAC3C,EAAK,iBAAiB,eAAe,CAAM,GAC3C,EAAK,iBAAiB,aAAa,CAAM,GACzC,EAAK,iBAAiB,iBAAiB,CAAM,GAC7C,EAAK,iBAAiB,gBAAgB,CAAM,SAC/B;GAMT,AALA,EAAO,GACP,EAAK,oBAAoB,eAAe,CAAM,GAC9C,EAAK,oBAAoB,eAAe,CAAM,GAC9C,EAAK,oBAAoB,aAAa,CAAM,GAC5C,EAAK,oBAAoB,iBAAiB,CAAM,GAChD,EAAK,oBAAoB,gBAAgB,CAAM;EACnD;CACJ,GAAG;EAAC;EAAK;EAAO;CAAa,CAAC;AAClC"}
@@ -1,2 +1,2 @@
1
- let e=require("react");function t(t={}){let{pingUrl:n,intervalMs:r=3e4,timeoutMs:i=5e3}=t,[a,o]=(0,e.useState)(()=>typeof navigator>`u`||navigator.onLine),[s,c]=(0,e.useState)(!0),l=(0,e.useRef)({pingUrl:n,timeoutMs:i});return l.current={pingUrl:n,timeoutMs:i},(0,e.useEffect)(()=>{if(typeof window>`u`)return;let e=()=>o(!0),t=()=>o(!1);return window.addEventListener(`online`,e),window.addEventListener(`offline`,t),()=>{window.removeEventListener(`online`,e),window.removeEventListener(`offline`,t)}},[]),(0,e.useEffect)(()=>{if(!n||typeof window>`u`)return;let e=!1,t=async()=>{if(typeof navigator<`u`&&!navigator.onLine){e||c(!1);return}let t=new AbortController,n=window.setTimeout(()=>t.abort(),l.current.timeoutMs);try{await fetch(l.current.pingUrl,{method:`HEAD`,cache:`no-store`,signal:t.signal}),e||c(!0)}catch{e||c(!1)}finally{window.clearTimeout(n)}};t();let i=window.setInterval(()=>void t(),r),a=()=>void t();return window.addEventListener(`online`,a),document.addEventListener(`visibilitychange`,a),()=>{e=!0,window.clearInterval(i),window.removeEventListener(`online`,a),document.removeEventListener(`visibilitychange`,a)}},[n,r]),n?a&&s:a}exports.useOnline=t;
1
+ let e=require("react");function t(t={}){let{pingUrl:n,intervalMs:r=3e4,timeoutMs:i=5e3}=t,[a,o]=(0,e.useState)(()=>typeof navigator>`u`||navigator.onLine),[s,c]=(0,e.useState)(!0),l=(0,e.useRef)({pingUrl:n,timeoutMs:i});return(0,e.useEffect)(()=>{l.current={pingUrl:n,timeoutMs:i}},[n,i]),(0,e.useEffect)(()=>{if(typeof window>`u`)return;let e=()=>o(!0),t=()=>o(!1);return window.addEventListener(`online`,e),window.addEventListener(`offline`,t),()=>{window.removeEventListener(`online`,e),window.removeEventListener(`offline`,t)}},[]),(0,e.useEffect)(()=>{if(!n||typeof window>`u`)return;let e=!1,t=async()=>{if(typeof navigator<`u`&&!navigator.onLine){e||c(!1);return}let t=new AbortController,n=window.setTimeout(()=>t.abort(),l.current.timeoutMs);try{await fetch(l.current.pingUrl,{method:`HEAD`,cache:`no-store`,signal:t.signal}),e||c(!0)}catch{e||c(!1)}finally{window.clearTimeout(n)}};t();let i=window.setInterval(()=>void t(),r),a=()=>void t();return window.addEventListener(`online`,a),document.addEventListener(`visibilitychange`,a),()=>{e=!0,window.clearInterval(i),window.removeEventListener(`online`,a),document.removeEventListener(`visibilitychange`,a)}},[n,r]),n?a&&s:a}exports.useOnline=t;
2
2
  //# sourceMappingURL=use-online.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-online.cjs","names":[],"sources":["../../src/hooks/use-online.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\n\n/**\n * Options for {@link useOnline}. Omit them for the cheap `navigator.onLine`\n * behaviour; pass `pingUrl` to add a real-reachability probe on top.\n */\nexport interface UseOnlineOptions {\n /**\n * URL to probe for real connectivity. `navigator.onLine` reports `true`\n * behind a captive portal or when the machine has a link but no internet;\n * a periodic `HEAD` to this URL catches those cases. When set, the result\n * is `navigator.onLine && lastProbeSucceeded`.\n */\n pingUrl?: string;\n /** How often to probe, in ms. Default `30000`. */\n intervalMs?: number;\n /** Abort a probe after this many ms and treat it as offline. Default `5000`. */\n timeoutMs?: number;\n}\n\n/**\n * Track connectivity and re-render on changes.\n *\n * With no options it mirrors `navigator.onLine` (assuming online during SSR and\n * before the first event). Pass `pingUrl` to additionally probe real\n * reachability — the browser's `onLine` flag lies behind captive portals and\n * dead links, so the probe downgrades the result to `false` when the network is\n * unusable even though `navigator.onLine` is `true`.\n *\n * @param options - Optional reachability-probe configuration.\n * @returns `true` when the device is online (and reachable, when probing).\n *\n * @example\n * const online = useOnline(); // navigator.onLine only\n * const reallyOnline = useOnline({ pingUrl: \"/health\", intervalMs: 15_000 });\n */\nexport function useOnline(options: UseOnlineOptions = {}): boolean {\n const { pingUrl, intervalMs = 30_000, timeoutMs = 5_000 } = options;\n\n const [navOnline, setNavOnline] = useState<boolean>(() =>\n typeof navigator === \"undefined\" ? true : navigator.onLine,\n );\n const [reachable, setReachable] = useState<boolean>(true);\n\n const optionsRef = useRef({ pingUrl, timeoutMs });\n optionsRef.current = { pingUrl, timeoutMs };\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const handleOnline = (): void => setNavOnline(true);\n const handleOffline = (): void => setNavOnline(false);\n window.addEventListener(\"online\", handleOnline);\n window.addEventListener(\"offline\", handleOffline);\n return () => {\n window.removeEventListener(\"online\", handleOnline);\n window.removeEventListener(\"offline\", handleOffline);\n };\n }, []);\n\n useEffect(() => {\n if (!pingUrl || typeof window === \"undefined\") return;\n\n let cancelled = false;\n const probe = async (): Promise<void> => {\n if (typeof navigator !== \"undefined\" && !navigator.onLine) {\n if (!cancelled) setReachable(false);\n return;\n }\n const controller = new AbortController();\n const timer = window.setTimeout(() => controller.abort(), optionsRef.current.timeoutMs);\n try {\n await fetch(optionsRef.current.pingUrl!, {\n method: \"HEAD\",\n cache: \"no-store\",\n signal: controller.signal,\n });\n if (!cancelled) setReachable(true);\n } catch {\n if (!cancelled) setReachable(false);\n } finally {\n window.clearTimeout(timer);\n }\n };\n\n void probe();\n const id = window.setInterval(() => void probe(), intervalMs);\n const onWake = (): void => void probe();\n window.addEventListener(\"online\", onWake);\n document.addEventListener(\"visibilitychange\", onWake);\n return () => {\n cancelled = true;\n window.clearInterval(id);\n window.removeEventListener(\"online\", onWake);\n document.removeEventListener(\"visibilitychange\", onWake);\n };\n }, [pingUrl, intervalMs]);\n\n return pingUrl ? navOnline && reachable : navOnline;\n}\n"],"mappings":"uBAoCA,SAAgB,EAAU,EAA4B,CAAC,EAAY,CAC/D,GAAM,CAAE,UAAS,aAAa,IAAQ,YAAY,KAAU,EAEtD,CAAC,EAAW,IAAA,EAAA,EAAA,SAAA,KACd,OAAO,UAAc,KAAqB,UAAU,MACxD,EACM,CAAC,EAAW,IAAA,EAAA,EAAA,SAAA,CAAkC,EAAI,EAElD,GAAA,EAAA,EAAA,OAAA,CAAoB,CAAE,UAAS,WAAU,CAAC,EAqDhD,MApDA,GAAW,QAAU,CAAE,UAAS,WAAU,GAE1C,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,MAA2B,EAAa,EAAI,EAC5C,MAA4B,EAAa,EAAK,EAGpD,OAFA,OAAO,iBAAiB,SAAU,CAAY,EAC9C,OAAO,iBAAiB,UAAW,CAAa,MACnC,CACT,OAAO,oBAAoB,SAAU,CAAY,EACjD,OAAO,oBAAoB,UAAW,CAAa,CACvD,CACJ,EAAG,CAAC,CAAC,GAEL,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,GAAW,OAAO,OAAW,IAAa,OAE/C,IAAI,EAAY,GACV,EAAQ,SAA2B,CACrC,GAAI,OAAO,UAAc,KAAe,CAAC,UAAU,OAAQ,CAClD,GAAW,EAAa,EAAK,EAClC,MACJ,CACA,IAAM,EAAa,IAAI,gBACjB,EAAQ,OAAO,eAAiB,EAAW,MAAM,EAAG,EAAW,QAAQ,SAAS,EACtF,GAAI,CACA,MAAM,MAAM,EAAW,QAAQ,QAAU,CACrC,OAAQ,OACR,MAAO,WACP,OAAQ,EAAW,MACvB,CAAC,EACI,GAAW,EAAa,EAAI,CACrC,MAAQ,CACC,GAAW,EAAa,EAAK,CACtC,QAAU,CACN,OAAO,aAAa,CAAK,CAC7B,CACJ,EAEA,EAAW,EACX,IAAM,EAAK,OAAO,gBAAkB,KAAK,EAAM,EAAG,CAAU,EACtD,MAAqB,KAAK,EAAM,EAGtC,OAFA,OAAO,iBAAiB,SAAU,CAAM,EACxC,SAAS,iBAAiB,mBAAoB,CAAM,MACvC,CACT,EAAY,GACZ,OAAO,cAAc,CAAE,EACvB,OAAO,oBAAoB,SAAU,CAAM,EAC3C,SAAS,oBAAoB,mBAAoB,CAAM,CAC3D,CACJ,EAAG,CAAC,EAAS,CAAU,CAAC,EAEjB,EAAU,GAAa,EAAY,CAC9C"}
1
+ {"version":3,"file":"use-online.cjs","names":[],"sources":["../../src/hooks/use-online.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\n\n/**\n * Options for {@link useOnline}. Omit them for the cheap `navigator.onLine`\n * behaviour; pass `pingUrl` to add a real-reachability probe on top.\n */\nexport interface UseOnlineOptions {\n /**\n * URL to probe for real connectivity. `navigator.onLine` reports `true`\n * behind a captive portal or when the machine has a link but no internet;\n * a periodic `HEAD` to this URL catches those cases. When set, the result\n * is `navigator.onLine && lastProbeSucceeded`.\n */\n pingUrl?: string;\n /** How often to probe, in ms. Default `30000`. */\n intervalMs?: number;\n /** Abort a probe after this many ms and treat it as offline. Default `5000`. */\n timeoutMs?: number;\n}\n\n/**\n * Track connectivity and re-render on changes.\n *\n * With no options it mirrors `navigator.onLine` (assuming online during SSR and\n * before the first event). Pass `pingUrl` to additionally probe real\n * reachability — the browser's `onLine` flag lies behind captive portals and\n * dead links, so the probe downgrades the result to `false` when the network is\n * unusable even though `navigator.onLine` is `true`.\n *\n * @param options - Optional reachability-probe configuration.\n * @returns `true` when the device is online (and reachable, when probing).\n *\n * @example\n * const online = useOnline(); // navigator.onLine only\n * const reallyOnline = useOnline({ pingUrl: \"/health\", intervalMs: 15_000 });\n */\nexport function useOnline(options: UseOnlineOptions = {}): boolean {\n const { pingUrl, intervalMs = 30_000, timeoutMs = 5_000 } = options;\n\n const [navOnline, setNavOnline] = useState<boolean>(() =>\n typeof navigator === \"undefined\" ? true : navigator.onLine,\n );\n const [reachable, setReachable] = useState<boolean>(true);\n\n const optionsRef = useRef({ pingUrl, timeoutMs });\n useEffect(() => {\n optionsRef.current = { pingUrl, timeoutMs };\n }, [pingUrl, timeoutMs]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const handleOnline = (): void => setNavOnline(true);\n const handleOffline = (): void => setNavOnline(false);\n window.addEventListener(\"online\", handleOnline);\n window.addEventListener(\"offline\", handleOffline);\n return () => {\n window.removeEventListener(\"online\", handleOnline);\n window.removeEventListener(\"offline\", handleOffline);\n };\n }, []);\n\n useEffect(() => {\n if (!pingUrl || typeof window === \"undefined\") return;\n\n let cancelled = false;\n const probe = async (): Promise<void> => {\n if (typeof navigator !== \"undefined\" && !navigator.onLine) {\n if (!cancelled) setReachable(false);\n return;\n }\n const controller = new AbortController();\n const timer = window.setTimeout(() => controller.abort(), optionsRef.current.timeoutMs);\n try {\n await fetch(optionsRef.current.pingUrl!, {\n method: \"HEAD\",\n cache: \"no-store\",\n signal: controller.signal,\n });\n if (!cancelled) setReachable(true);\n } catch {\n if (!cancelled) setReachable(false);\n } finally {\n window.clearTimeout(timer);\n }\n };\n\n void probe();\n const id = window.setInterval(() => void probe(), intervalMs);\n const onWake = (): void => void probe();\n window.addEventListener(\"online\", onWake);\n document.addEventListener(\"visibilitychange\", onWake);\n return () => {\n cancelled = true;\n window.clearInterval(id);\n window.removeEventListener(\"online\", onWake);\n document.removeEventListener(\"visibilitychange\", onWake);\n };\n }, [pingUrl, intervalMs]);\n\n return pingUrl ? navOnline && reachable : navOnline;\n}\n"],"mappings":"uBAoCA,SAAgB,EAAU,EAA4B,CAAC,EAAY,CAC/D,GAAM,CAAE,UAAS,aAAa,IAAQ,YAAY,KAAU,EAEtD,CAAC,EAAW,IAAA,EAAA,EAAA,SAAA,KACd,OAAO,UAAc,KAAqB,UAAU,MACxD,EACM,CAAC,EAAW,IAAA,EAAA,EAAA,SAAA,CAAkC,EAAI,EAElD,GAAA,EAAA,EAAA,OAAA,CAAoB,CAAE,UAAS,WAAU,CAAC,EAuDhD,OAtDA,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAW,QAAU,CAAE,UAAS,WAAU,CAC9C,EAAG,CAAC,EAAS,CAAS,CAAC,GAEvB,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,MAA2B,EAAa,EAAI,EAC5C,MAA4B,EAAa,EAAK,EAGpD,OAFA,OAAO,iBAAiB,SAAU,CAAY,EAC9C,OAAO,iBAAiB,UAAW,CAAa,MACnC,CACT,OAAO,oBAAoB,SAAU,CAAY,EACjD,OAAO,oBAAoB,UAAW,CAAa,CACvD,CACJ,EAAG,CAAC,CAAC,GAEL,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,GAAW,OAAO,OAAW,IAAa,OAE/C,IAAI,EAAY,GACV,EAAQ,SAA2B,CACrC,GAAI,OAAO,UAAc,KAAe,CAAC,UAAU,OAAQ,CAClD,GAAW,EAAa,EAAK,EAClC,MACJ,CACA,IAAM,EAAa,IAAI,gBACjB,EAAQ,OAAO,eAAiB,EAAW,MAAM,EAAG,EAAW,QAAQ,SAAS,EACtF,GAAI,CACA,MAAM,MAAM,EAAW,QAAQ,QAAU,CACrC,OAAQ,OACR,MAAO,WACP,OAAQ,EAAW,MACvB,CAAC,EACI,GAAW,EAAa,EAAI,CACrC,MAAQ,CACC,GAAW,EAAa,EAAK,CACtC,QAAU,CACN,OAAO,aAAa,CAAK,CAC7B,CACJ,EAEA,EAAW,EACX,IAAM,EAAK,OAAO,gBAAkB,KAAK,EAAM,EAAG,CAAU,EACtD,MAAqB,KAAK,EAAM,EAGtC,OAFA,OAAO,iBAAiB,SAAU,CAAM,EACxC,SAAS,iBAAiB,mBAAoB,CAAM,MACvC,CACT,EAAY,GACZ,OAAO,cAAc,CAAE,EACvB,OAAO,oBAAoB,SAAU,CAAM,EAC3C,SAAS,oBAAoB,mBAAoB,CAAM,CAC3D,CACJ,EAAG,CAAC,EAAS,CAAU,CAAC,EAEjB,EAAU,GAAa,EAAY,CAC9C"}
@@ -5,10 +5,12 @@ function r(r = {}) {
5
5
  pingUrl: i,
6
6
  timeoutMs: o
7
7
  });
8
- return d.current = {
9
- pingUrl: i,
10
- timeoutMs: o
11
- }, e(() => {
8
+ return e(() => {
9
+ d.current = {
10
+ pingUrl: i,
11
+ timeoutMs: o
12
+ };
13
+ }, [i, o]), e(() => {
12
14
  if (typeof window > "u") return;
13
15
  let e = () => c(!0), t = () => c(!1);
14
16
  return window.addEventListener("online", e), window.addEventListener("offline", t), () => {
@@ -1 +1 @@
1
- {"version":3,"file":"use-online.js","names":[],"sources":["../../src/hooks/use-online.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\n\n/**\n * Options for {@link useOnline}. Omit them for the cheap `navigator.onLine`\n * behaviour; pass `pingUrl` to add a real-reachability probe on top.\n */\nexport interface UseOnlineOptions {\n /**\n * URL to probe for real connectivity. `navigator.onLine` reports `true`\n * behind a captive portal or when the machine has a link but no internet;\n * a periodic `HEAD` to this URL catches those cases. When set, the result\n * is `navigator.onLine && lastProbeSucceeded`.\n */\n pingUrl?: string;\n /** How often to probe, in ms. Default `30000`. */\n intervalMs?: number;\n /** Abort a probe after this many ms and treat it as offline. Default `5000`. */\n timeoutMs?: number;\n}\n\n/**\n * Track connectivity and re-render on changes.\n *\n * With no options it mirrors `navigator.onLine` (assuming online during SSR and\n * before the first event). Pass `pingUrl` to additionally probe real\n * reachability — the browser's `onLine` flag lies behind captive portals and\n * dead links, so the probe downgrades the result to `false` when the network is\n * unusable even though `navigator.onLine` is `true`.\n *\n * @param options - Optional reachability-probe configuration.\n * @returns `true` when the device is online (and reachable, when probing).\n *\n * @example\n * const online = useOnline(); // navigator.onLine only\n * const reallyOnline = useOnline({ pingUrl: \"/health\", intervalMs: 15_000 });\n */\nexport function useOnline(options: UseOnlineOptions = {}): boolean {\n const { pingUrl, intervalMs = 30_000, timeoutMs = 5_000 } = options;\n\n const [navOnline, setNavOnline] = useState<boolean>(() =>\n typeof navigator === \"undefined\" ? true : navigator.onLine,\n );\n const [reachable, setReachable] = useState<boolean>(true);\n\n const optionsRef = useRef({ pingUrl, timeoutMs });\n optionsRef.current = { pingUrl, timeoutMs };\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const handleOnline = (): void => setNavOnline(true);\n const handleOffline = (): void => setNavOnline(false);\n window.addEventListener(\"online\", handleOnline);\n window.addEventListener(\"offline\", handleOffline);\n return () => {\n window.removeEventListener(\"online\", handleOnline);\n window.removeEventListener(\"offline\", handleOffline);\n };\n }, []);\n\n useEffect(() => {\n if (!pingUrl || typeof window === \"undefined\") return;\n\n let cancelled = false;\n const probe = async (): Promise<void> => {\n if (typeof navigator !== \"undefined\" && !navigator.onLine) {\n if (!cancelled) setReachable(false);\n return;\n }\n const controller = new AbortController();\n const timer = window.setTimeout(() => controller.abort(), optionsRef.current.timeoutMs);\n try {\n await fetch(optionsRef.current.pingUrl!, {\n method: \"HEAD\",\n cache: \"no-store\",\n signal: controller.signal,\n });\n if (!cancelled) setReachable(true);\n } catch {\n if (!cancelled) setReachable(false);\n } finally {\n window.clearTimeout(timer);\n }\n };\n\n void probe();\n const id = window.setInterval(() => void probe(), intervalMs);\n const onWake = (): void => void probe();\n window.addEventListener(\"online\", onWake);\n document.addEventListener(\"visibilitychange\", onWake);\n return () => {\n cancelled = true;\n window.clearInterval(id);\n window.removeEventListener(\"online\", onWake);\n document.removeEventListener(\"visibilitychange\", onWake);\n };\n }, [pingUrl, intervalMs]);\n\n return pingUrl ? navOnline && reachable : navOnline;\n}\n"],"mappings":";;AAoCA,SAAgB,EAAU,IAA4B,CAAC,GAAY;CAC/D,IAAM,EAAE,YAAS,gBAAa,KAAQ,eAAY,QAAU,GAEtD,CAAC,GAAW,KAAgB,QAC9B,OAAO,YAAc,OAAqB,UAAU,MACxD,GACM,CAAC,GAAW,KAAgB,EAAkB,EAAI,GAElD,IAAa,EAAO;EAAE;EAAS;CAAU,CAAC;CAqDhD,OApDA,EAAW,UAAU;EAAE;EAAS;CAAU,GAE1C,QAAgB;EACZ,IAAI,OAAO,SAAW,KAAa;EACnC,IAAM,UAA2B,EAAa,EAAI,GAC5C,UAA4B,EAAa,EAAK;EAGpD,OAFA,OAAO,iBAAiB,UAAU,CAAY,GAC9C,OAAO,iBAAiB,WAAW,CAAa,SACnC;GAET,AADA,OAAO,oBAAoB,UAAU,CAAY,GACjD,OAAO,oBAAoB,WAAW,CAAa;EACvD;CACJ,GAAG,CAAC,CAAC,GAEL,QAAgB;EACZ,IAAI,CAAC,KAAW,OAAO,SAAW,KAAa;EAE/C,IAAI,IAAY,IACV,IAAQ,YAA2B;GACrC,IAAI,OAAO,YAAc,OAAe,CAAC,UAAU,QAAQ;IACvD,AAAK,KAAW,EAAa,EAAK;IAClC;GACJ;GACA,IAAM,IAAa,IAAI,gBAAgB,GACjC,IAAQ,OAAO,iBAAiB,EAAW,MAAM,GAAG,EAAW,QAAQ,SAAS;GACtF,IAAI;IAMA,AALA,MAAM,MAAM,EAAW,QAAQ,SAAU;KACrC,QAAQ;KACR,OAAO;KACP,QAAQ,EAAW;IACvB,CAAC,GACI,KAAW,EAAa,EAAI;GACrC,QAAQ;IACJ,AAAK,KAAW,EAAa,EAAK;GACtC,UAAU;IACN,OAAO,aAAa,CAAK;GAC7B;EACJ;EAEA,EAAW;EACX,IAAM,IAAK,OAAO,kBAAkB,KAAK,EAAM,GAAG,CAAU,GACtD,UAAqB,KAAK,EAAM;EAGtC,OAFA,OAAO,iBAAiB,UAAU,CAAM,GACxC,SAAS,iBAAiB,oBAAoB,CAAM,SACvC;GAIT,AAHA,IAAY,IACZ,OAAO,cAAc,CAAE,GACvB,OAAO,oBAAoB,UAAU,CAAM,GAC3C,SAAS,oBAAoB,oBAAoB,CAAM;EAC3D;CACJ,GAAG,CAAC,GAAS,CAAU,CAAC,GAEjB,IAAU,KAAa,IAAY;AAC9C"}
1
+ {"version":3,"file":"use-online.js","names":[],"sources":["../../src/hooks/use-online.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\n\n/**\n * Options for {@link useOnline}. Omit them for the cheap `navigator.onLine`\n * behaviour; pass `pingUrl` to add a real-reachability probe on top.\n */\nexport interface UseOnlineOptions {\n /**\n * URL to probe for real connectivity. `navigator.onLine` reports `true`\n * behind a captive portal or when the machine has a link but no internet;\n * a periodic `HEAD` to this URL catches those cases. When set, the result\n * is `navigator.onLine && lastProbeSucceeded`.\n */\n pingUrl?: string;\n /** How often to probe, in ms. Default `30000`. */\n intervalMs?: number;\n /** Abort a probe after this many ms and treat it as offline. Default `5000`. */\n timeoutMs?: number;\n}\n\n/**\n * Track connectivity and re-render on changes.\n *\n * With no options it mirrors `navigator.onLine` (assuming online during SSR and\n * before the first event). Pass `pingUrl` to additionally probe real\n * reachability — the browser's `onLine` flag lies behind captive portals and\n * dead links, so the probe downgrades the result to `false` when the network is\n * unusable even though `navigator.onLine` is `true`.\n *\n * @param options - Optional reachability-probe configuration.\n * @returns `true` when the device is online (and reachable, when probing).\n *\n * @example\n * const online = useOnline(); // navigator.onLine only\n * const reallyOnline = useOnline({ pingUrl: \"/health\", intervalMs: 15_000 });\n */\nexport function useOnline(options: UseOnlineOptions = {}): boolean {\n const { pingUrl, intervalMs = 30_000, timeoutMs = 5_000 } = options;\n\n const [navOnline, setNavOnline] = useState<boolean>(() =>\n typeof navigator === \"undefined\" ? true : navigator.onLine,\n );\n const [reachable, setReachable] = useState<boolean>(true);\n\n const optionsRef = useRef({ pingUrl, timeoutMs });\n useEffect(() => {\n optionsRef.current = { pingUrl, timeoutMs };\n }, [pingUrl, timeoutMs]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const handleOnline = (): void => setNavOnline(true);\n const handleOffline = (): void => setNavOnline(false);\n window.addEventListener(\"online\", handleOnline);\n window.addEventListener(\"offline\", handleOffline);\n return () => {\n window.removeEventListener(\"online\", handleOnline);\n window.removeEventListener(\"offline\", handleOffline);\n };\n }, []);\n\n useEffect(() => {\n if (!pingUrl || typeof window === \"undefined\") return;\n\n let cancelled = false;\n const probe = async (): Promise<void> => {\n if (typeof navigator !== \"undefined\" && !navigator.onLine) {\n if (!cancelled) setReachable(false);\n return;\n }\n const controller = new AbortController();\n const timer = window.setTimeout(() => controller.abort(), optionsRef.current.timeoutMs);\n try {\n await fetch(optionsRef.current.pingUrl!, {\n method: \"HEAD\",\n cache: \"no-store\",\n signal: controller.signal,\n });\n if (!cancelled) setReachable(true);\n } catch {\n if (!cancelled) setReachable(false);\n } finally {\n window.clearTimeout(timer);\n }\n };\n\n void probe();\n const id = window.setInterval(() => void probe(), intervalMs);\n const onWake = (): void => void probe();\n window.addEventListener(\"online\", onWake);\n document.addEventListener(\"visibilitychange\", onWake);\n return () => {\n cancelled = true;\n window.clearInterval(id);\n window.removeEventListener(\"online\", onWake);\n document.removeEventListener(\"visibilitychange\", onWake);\n };\n }, [pingUrl, intervalMs]);\n\n return pingUrl ? navOnline && reachable : navOnline;\n}\n"],"mappings":";;AAoCA,SAAgB,EAAU,IAA4B,CAAC,GAAY;CAC/D,IAAM,EAAE,YAAS,gBAAa,KAAQ,eAAY,QAAU,GAEtD,CAAC,GAAW,KAAgB,QAC9B,OAAO,YAAc,OAAqB,UAAU,MACxD,GACM,CAAC,GAAW,KAAgB,EAAkB,EAAI,GAElD,IAAa,EAAO;EAAE;EAAS;CAAU,CAAC;CAuDhD,OAtDA,QAAgB;EACZ,EAAW,UAAU;GAAE;GAAS;EAAU;CAC9C,GAAG,CAAC,GAAS,CAAS,CAAC,GAEvB,QAAgB;EACZ,IAAI,OAAO,SAAW,KAAa;EACnC,IAAM,UAA2B,EAAa,EAAI,GAC5C,UAA4B,EAAa,EAAK;EAGpD,OAFA,OAAO,iBAAiB,UAAU,CAAY,GAC9C,OAAO,iBAAiB,WAAW,CAAa,SACnC;GAET,AADA,OAAO,oBAAoB,UAAU,CAAY,GACjD,OAAO,oBAAoB,WAAW,CAAa;EACvD;CACJ,GAAG,CAAC,CAAC,GAEL,QAAgB;EACZ,IAAI,CAAC,KAAW,OAAO,SAAW,KAAa;EAE/C,IAAI,IAAY,IACV,IAAQ,YAA2B;GACrC,IAAI,OAAO,YAAc,OAAe,CAAC,UAAU,QAAQ;IACvD,AAAK,KAAW,EAAa,EAAK;IAClC;GACJ;GACA,IAAM,IAAa,IAAI,gBAAgB,GACjC,IAAQ,OAAO,iBAAiB,EAAW,MAAM,GAAG,EAAW,QAAQ,SAAS;GACtF,IAAI;IAMA,AALA,MAAM,MAAM,EAAW,QAAQ,SAAU;KACrC,QAAQ;KACR,OAAO;KACP,QAAQ,EAAW;IACvB,CAAC,GACI,KAAW,EAAa,EAAI;GACrC,QAAQ;IACJ,AAAK,KAAW,EAAa,EAAK;GACtC,UAAU;IACN,OAAO,aAAa,CAAK;GAC7B;EACJ;EAEA,EAAW;EACX,IAAM,IAAK,OAAO,kBAAkB,KAAK,EAAM,GAAG,CAAU,GACtD,UAAqB,KAAK,EAAM;EAGtC,OAFA,OAAO,iBAAiB,UAAU,CAAM,GACxC,SAAS,iBAAiB,oBAAoB,CAAM,SACvC;GAIT,AAHA,IAAY,IACZ,OAAO,cAAc,CAAE,GACvB,OAAO,oBAAoB,UAAU,CAAM,GAC3C,SAAS,oBAAoB,oBAAoB,CAAM;EAC3D;CACJ,GAAG,CAAC,GAAS,CAAU,CAAC,GAEjB,IAAU,KAAa,IAAY;AAC9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-previous.cjs","names":[],"sources":["../../src/hooks/use-previous.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\n\n/**\n * Return the value from the previous render. `undefined` on the first render.\n *\n * @example\n * const previousCount = usePrevious(count);\n * useEffect(() => {\n * if (previousCount !== undefined && previousCount !== count) {\n * analytics.track(\"count.changed\", { from: previousCount, to: count });\n * }\n * }, [count, previousCount]);\n */\nexport function usePrevious<T>(value: T): T | undefined {\n const ref = useRef<T | undefined>(undefined);\n useEffect(() => {\n ref.current = value;\n }, [value]);\n return ref.current;\n}\n"],"mappings":"uBAaA,SAAgB,EAAe,EAAyB,CACpD,IAAM,GAAA,EAAA,EAAA,OAAA,CAA4B,IAAA,EAAS,EAI3C,OAHA,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAI,QAAU,CAClB,EAAG,CAAC,CAAK,CAAC,EACH,EAAI,OACf"}
1
+ {"version":3,"file":"use-previous.cjs","names":[],"sources":["../../src/hooks/use-previous.ts"],"sourcesContent":["/* eslint-disable react-hooks/refs -- returning last render's value IS this hook's contract */\nimport { useEffect, useRef } from \"react\";\n\n/**\n * Return the value from the previous render. `undefined` on the first render.\n *\n * @example\n * const previousCount = usePrevious(count);\n * useEffect(() => {\n * if (previousCount !== undefined && previousCount !== count) {\n * analytics.track(\"count.changed\", { from: previousCount, to: count });\n * }\n * }, [count, previousCount]);\n */\nexport function usePrevious<T>(value: T): T | undefined {\n const ref = useRef<T | undefined>(undefined);\n useEffect(() => {\n ref.current = value;\n }, [value]);\n return ref.current;\n}\n"],"mappings":"uBAcA,SAAgB,EAAe,EAAyB,CACpD,IAAM,GAAA,EAAA,EAAA,OAAA,CAA4B,IAAA,EAAS,EAI3C,OAHA,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAI,QAAU,CAClB,EAAG,CAAC,CAAK,CAAC,EACH,EAAI,OACf"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-previous.js","names":[],"sources":["../../src/hooks/use-previous.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\n\n/**\n * Return the value from the previous render. `undefined` on the first render.\n *\n * @example\n * const previousCount = usePrevious(count);\n * useEffect(() => {\n * if (previousCount !== undefined && previousCount !== count) {\n * analytics.track(\"count.changed\", { from: previousCount, to: count });\n * }\n * }, [count, previousCount]);\n */\nexport function usePrevious<T>(value: T): T | undefined {\n const ref = useRef<T | undefined>(undefined);\n useEffect(() => {\n ref.current = value;\n }, [value]);\n return ref.current;\n}\n"],"mappings":";;AAaA,SAAgB,EAAe,GAAyB;CACpD,IAAM,IAAM,EAAsB,KAAA,CAAS;CAI3C,OAHA,QAAgB;EACZ,EAAI,UAAU;CAClB,GAAG,CAAC,CAAK,CAAC,GACH,EAAI;AACf"}
1
+ {"version":3,"file":"use-previous.js","names":[],"sources":["../../src/hooks/use-previous.ts"],"sourcesContent":["/* eslint-disable react-hooks/refs -- returning last render's value IS this hook's contract */\nimport { useEffect, useRef } from \"react\";\n\n/**\n * Return the value from the previous render. `undefined` on the first render.\n *\n * @example\n * const previousCount = usePrevious(count);\n * useEffect(() => {\n * if (previousCount !== undefined && previousCount !== count) {\n * analytics.track(\"count.changed\", { from: previousCount, to: count });\n * }\n * }, [count, previousCount]);\n */\nexport function usePrevious<T>(value: T): T | undefined {\n const ref = useRef<T | undefined>(undefined);\n useEffect(() => {\n ref.current = value;\n }, [value]);\n return ref.current;\n}\n"],"mappings":";;AAcA,SAAgB,EAAe,GAAyB;CACpD,IAAM,IAAM,EAAsB,KAAA,CAAS;CAI3C,OAHA,QAAgB;EACZ,EAAI,UAAU;CAClB,GAAG,CAAC,CAAK,CAAC,GACH,EAAI;AACf"}
@@ -1,2 +1,2 @@
1
- const e=require("../sw/register-service-worker.cjs");let t=require("react");function n(n){let[r,i]=(0,t.useState)(!1),[a,o]=(0,t.useState)(null),s=(0,t.useRef)(null),c=(0,t.useRef)(n);return c.current=n,(0,t.useEffect)(()=>{let t=!1;return e.registerServiceWorker({...c.current,onUpdate:(e,t)=>{s.current=e,o(t),i(!0)},onReady:e=>{t||(o(e),e.waiting&&navigator.serviceWorker.controller&&(s.current=e.waiting,i(!0)),c.current.onReady?.(e))}}).then(e=>{!t&&e&&o(e)}),()=>{t=!0}},[n.url]),{updateAvailable:r,applyUpdate:(0,t.useCallback)(()=>{let t=s.current;if(!t||typeof navigator>`u`)return;let n=!1;navigator.serviceWorker.addEventListener(`controllerchange`,()=>{n||(n=!0,window.location.reload())}),e.skipWaiting(t)},[]),registration:a}}exports.useServiceWorkerUpdate=n;
1
+ const e=require("../sw/register-service-worker.cjs");let t=require("react");function n(n){let[r,i]=(0,t.useState)(!1),[a,o]=(0,t.useState)(null),s=(0,t.useRef)(null),c=(0,t.useRef)(n);return(0,t.useEffect)(()=>{c.current=n},[n]),(0,t.useEffect)(()=>{let t=!1;return e.registerServiceWorker({...c.current,onUpdate:(e,t)=>{s.current=e,o(t),i(!0)},onReady:e=>{t||(o(e),e.waiting&&navigator.serviceWorker.controller&&(s.current=e.waiting,i(!0)),c.current.onReady?.(e))}}).then(e=>{!t&&e&&o(e)}),()=>{t=!0}},[n.url]),{updateAvailable:r,applyUpdate:(0,t.useCallback)(()=>{let t=s.current;if(!t||typeof navigator>`u`)return;let n=!1;navigator.serviceWorker.addEventListener(`controllerchange`,()=>{n||(n=!0,window.location.reload())}),e.skipWaiting(t)},[]),registration:a}}exports.useServiceWorkerUpdate=n;
2
2
  //# sourceMappingURL=use-service-worker-update.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-service-worker-update.cjs","names":[],"sources":["../../src/hooks/use-service-worker-update.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n registerServiceWorker,\n skipWaiting,\n type RegisterServiceWorkerOptions,\n} from \"../sw/register-service-worker\";\n\n/**\n * Options for {@link useServiceWorkerUpdate}. Mirrors the registration options\n * minus the callbacks the hook owns internally (`onUpdate`); `onReady` and\n * `onError` still pass through for host-side logging.\n *\n * Leave `autoUpdate` off (the default): this hook exists to hand the reload\n * decision to the user, so a silent auto-reload would defeat the prompt.\n */\nexport type UseServiceWorkerUpdateOptions = Omit<RegisterServiceWorkerOptions, \"onUpdate\">;\n\n/** Reactive service-worker update state plus the apply action. */\nexport interface UseServiceWorkerUpdateResult {\n /** `true` once a new worker has installed and is waiting to activate. */\n updateAvailable: boolean;\n /**\n * Activate the waiting worker and reload the page once it takes control.\n * No-op when no update is waiting.\n */\n applyUpdate: () => void;\n /** The active registration, or `null` before it resolves / when unsupported. */\n registration: ServiceWorkerRegistration | null;\n}\n\n/**\n * Register a service worker and expose a user-driven update flow.\n *\n * Wraps {@link registerServiceWorker}: when a fresh worker finishes installing\n * while the page is still controlled by the old one, `updateAvailable` flips to\n * `true`. Call `applyUpdate` — typically from an \"atualizar\" toast — to tell the\n * waiting worker to activate and reload the page once it takes control.\n *\n * Skips cleanly when the runtime has no service-worker support (`registration`\n * stays `null`, `updateAvailable` stays `false`).\n *\n * @param options - Registration options (`url` required); `autoUpdate` should\n * stay off so the reload is user-confirmed.\n * @returns The update state and `applyUpdate` action.\n *\n * @example\n * const { updateAvailable, applyUpdate } = useServiceWorkerUpdate({ url: \"/sw.js\" });\n * return (\n * <UpdatePrompt open={updateAvailable} onUpdate={applyUpdate} />\n * );\n */\nexport function useServiceWorkerUpdate(\n options: UseServiceWorkerUpdateOptions,\n): UseServiceWorkerUpdateResult {\n const [updateAvailable, setUpdateAvailable] = useState<boolean>(false);\n const [registration, setRegistration] = useState<ServiceWorkerRegistration | null>(null);\n const waitingRef = useRef<ServiceWorker | null>(null);\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n useEffect(() => {\n let cancelled = false;\n void registerServiceWorker({\n ...optionsRef.current,\n onUpdate: (waiting, reg) => {\n waitingRef.current = waiting;\n setRegistration(reg);\n setUpdateAvailable(true);\n },\n onReady: (reg) => {\n if (cancelled) return;\n setRegistration(reg);\n if (reg.waiting && navigator.serviceWorker.controller) {\n waitingRef.current = reg.waiting;\n setUpdateAvailable(true);\n }\n optionsRef.current.onReady?.(reg);\n },\n }).then((reg) => {\n if (!cancelled && reg) setRegistration(reg);\n });\n return () => {\n cancelled = true;\n };\n }, [options.url]);\n\n const applyUpdate = useCallback(() => {\n const waiting = waitingRef.current;\n if (!waiting || typeof navigator === \"undefined\") return;\n let reloading = false;\n navigator.serviceWorker.addEventListener(\"controllerchange\", () => {\n if (reloading) return;\n reloading = true;\n window.location.reload();\n });\n skipWaiting(waiting);\n }, []);\n\n return { updateAvailable, applyUpdate, registration };\n}\n"],"mappings":"4EAmDA,SAAgB,EACZ,EAC4B,CAC5B,GAAM,CAAC,EAAiB,IAAA,EAAA,EAAA,SAAA,CAAwC,EAAK,EAC/D,CAAC,EAAc,IAAA,EAAA,EAAA,SAAA,CAA8D,IAAI,EACjF,GAAA,EAAA,EAAA,OAAA,CAA0C,IAAI,EAE9C,GAAA,EAAA,EAAA,OAAA,CAAoB,CAAO,EAyCjC,MAxCA,GAAW,QAAU,GAErB,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAI,EAAY,GAoBhB,OAnBA,EAAK,sBAAsB,CACvB,GAAG,EAAW,QACd,UAAW,EAAS,IAAQ,CACxB,EAAW,QAAU,EACrB,EAAgB,CAAG,EACnB,EAAmB,EAAI,CAC3B,EACA,QAAU,GAAQ,CACV,IACJ,EAAgB,CAAG,EACf,EAAI,SAAW,UAAU,cAAc,aACvC,EAAW,QAAU,EAAI,QACzB,EAAmB,EAAI,GAE3B,EAAW,QAAQ,UAAU,CAAG,EACpC,CACJ,CAAC,CAAC,CAAC,KAAM,GAAQ,CACT,CAAC,GAAa,GAAK,EAAgB,CAAG,CAC9C,CAAC,MACY,CACT,EAAY,EAChB,CACJ,EAAG,CAAC,EAAQ,GAAG,CAAC,EAcT,CAAE,kBAAiB,aAAA,EAAA,EAAA,YAAA,KAZY,CAClC,IAAM,EAAU,EAAW,QAC3B,GAAI,CAAC,GAAW,OAAO,UAAc,IAAa,OAClD,IAAI,EAAY,GAChB,UAAU,cAAc,iBAAiB,uBAA0B,CAC3D,IACJ,EAAY,GACZ,OAAO,SAAS,OAAO,EAC3B,CAAC,EACD,EAAA,YAAY,CAAO,CACvB,EAAG,CAAC,CAEsB,EAAa,cAAa,CACxD"}
1
+ {"version":3,"file":"use-service-worker-update.cjs","names":[],"sources":["../../src/hooks/use-service-worker-update.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n registerServiceWorker,\n skipWaiting,\n type RegisterServiceWorkerOptions,\n} from \"../sw/register-service-worker\";\n\n/**\n * Options for {@link useServiceWorkerUpdate}. Mirrors the registration options\n * minus the callbacks the hook owns internally (`onUpdate`); `onReady` and\n * `onError` still pass through for host-side logging.\n *\n * Leave `autoUpdate` off (the default): this hook exists to hand the reload\n * decision to the user, so a silent auto-reload would defeat the prompt.\n */\nexport type UseServiceWorkerUpdateOptions = Omit<RegisterServiceWorkerOptions, \"onUpdate\">;\n\n/** Reactive service-worker update state plus the apply action. */\nexport interface UseServiceWorkerUpdateResult {\n /** `true` once a new worker has installed and is waiting to activate. */\n updateAvailable: boolean;\n /**\n * Activate the waiting worker and reload the page once it takes control.\n * No-op when no update is waiting.\n */\n applyUpdate: () => void;\n /** The active registration, or `null` before it resolves / when unsupported. */\n registration: ServiceWorkerRegistration | null;\n}\n\n/**\n * Register a service worker and expose a user-driven update flow.\n *\n * Wraps {@link registerServiceWorker}: when a fresh worker finishes installing\n * while the page is still controlled by the old one, `updateAvailable` flips to\n * `true`. Call `applyUpdate` — typically from an \"atualizar\" toast — to tell the\n * waiting worker to activate and reload the page once it takes control.\n *\n * Skips cleanly when the runtime has no service-worker support (`registration`\n * stays `null`, `updateAvailable` stays `false`).\n *\n * @param options - Registration options (`url` required); `autoUpdate` should\n * stay off so the reload is user-confirmed.\n * @returns The update state and `applyUpdate` action.\n *\n * @example\n * const { updateAvailable, applyUpdate } = useServiceWorkerUpdate({ url: \"/sw.js\" });\n * return (\n * <UpdatePrompt open={updateAvailable} onUpdate={applyUpdate} />\n * );\n */\nexport function useServiceWorkerUpdate(\n options: UseServiceWorkerUpdateOptions,\n): UseServiceWorkerUpdateResult {\n const [updateAvailable, setUpdateAvailable] = useState<boolean>(false);\n const [registration, setRegistration] = useState<ServiceWorkerRegistration | null>(null);\n const waitingRef = useRef<ServiceWorker | null>(null);\n\n const optionsRef = useRef(options);\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n useEffect(() => {\n let cancelled = false;\n void registerServiceWorker({\n ...optionsRef.current,\n onUpdate: (waiting, reg) => {\n waitingRef.current = waiting;\n setRegistration(reg);\n setUpdateAvailable(true);\n },\n onReady: (reg) => {\n if (cancelled) return;\n setRegistration(reg);\n if (reg.waiting && navigator.serviceWorker.controller) {\n waitingRef.current = reg.waiting;\n setUpdateAvailable(true);\n }\n optionsRef.current.onReady?.(reg);\n },\n }).then((reg) => {\n if (!cancelled && reg) setRegistration(reg);\n });\n return () => {\n cancelled = true;\n };\n }, [options.url]);\n\n const applyUpdate = useCallback(() => {\n const waiting = waitingRef.current;\n if (!waiting || typeof navigator === \"undefined\") return;\n let reloading = false;\n navigator.serviceWorker.addEventListener(\"controllerchange\", () => {\n if (reloading) return;\n reloading = true;\n window.location.reload();\n });\n skipWaiting(waiting);\n }, []);\n\n return { updateAvailable, applyUpdate, registration };\n}\n"],"mappings":"4EAmDA,SAAgB,EACZ,EAC4B,CAC5B,GAAM,CAAC,EAAiB,IAAA,EAAA,EAAA,SAAA,CAAwC,EAAK,EAC/D,CAAC,EAAc,IAAA,EAAA,EAAA,SAAA,CAA8D,IAAI,EACjF,GAAA,EAAA,EAAA,OAAA,CAA0C,IAAI,EAE9C,GAAA,EAAA,EAAA,OAAA,CAAoB,CAAO,EA2CjC,OA1CA,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAW,QAAU,CACzB,EAAG,CAAC,CAAO,CAAC,GAEZ,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAI,EAAY,GAoBhB,OAnBA,EAAK,sBAAsB,CACvB,GAAG,EAAW,QACd,UAAW,EAAS,IAAQ,CACxB,EAAW,QAAU,EACrB,EAAgB,CAAG,EACnB,EAAmB,EAAI,CAC3B,EACA,QAAU,GAAQ,CACV,IACJ,EAAgB,CAAG,EACf,EAAI,SAAW,UAAU,cAAc,aACvC,EAAW,QAAU,EAAI,QACzB,EAAmB,EAAI,GAE3B,EAAW,QAAQ,UAAU,CAAG,EACpC,CACJ,CAAC,CAAC,CAAC,KAAM,GAAQ,CACT,CAAC,GAAa,GAAK,EAAgB,CAAG,CAC9C,CAAC,MACY,CACT,EAAY,EAChB,CACJ,EAAG,CAAC,EAAQ,GAAG,CAAC,EAcT,CAAE,kBAAiB,aAAA,EAAA,EAAA,YAAA,KAZY,CAClC,IAAM,EAAU,EAAW,QAC3B,GAAI,CAAC,GAAW,OAAO,UAAc,IAAa,OAClD,IAAI,EAAY,GAChB,UAAU,cAAc,iBAAiB,uBAA0B,CAC3D,IACJ,EAAY,GACZ,OAAO,SAAS,OAAO,EAC3B,CAAC,EACD,EAAA,YAAY,CAAO,CACvB,EAAG,CAAC,CAEsB,EAAa,cAAa,CACxD"}
@@ -3,7 +3,9 @@ import { useCallback as n, useEffect as r, useRef as i, useState as a } from "re
3
3
  //#region src/hooks/use-service-worker-update.ts
4
4
  function o(o) {
5
5
  let [s, c] = a(!1), [l, u] = a(null), d = i(null), f = i(o);
6
- return f.current = o, r(() => {
6
+ return r(() => {
7
+ f.current = o;
8
+ }, [o]), r(() => {
7
9
  let t = !1;
8
10
  return e({
9
11
  ...f.current,
@@ -1 +1 @@
1
- {"version":3,"file":"use-service-worker-update.js","names":[],"sources":["../../src/hooks/use-service-worker-update.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n registerServiceWorker,\n skipWaiting,\n type RegisterServiceWorkerOptions,\n} from \"../sw/register-service-worker\";\n\n/**\n * Options for {@link useServiceWorkerUpdate}. Mirrors the registration options\n * minus the callbacks the hook owns internally (`onUpdate`); `onReady` and\n * `onError` still pass through for host-side logging.\n *\n * Leave `autoUpdate` off (the default): this hook exists to hand the reload\n * decision to the user, so a silent auto-reload would defeat the prompt.\n */\nexport type UseServiceWorkerUpdateOptions = Omit<RegisterServiceWorkerOptions, \"onUpdate\">;\n\n/** Reactive service-worker update state plus the apply action. */\nexport interface UseServiceWorkerUpdateResult {\n /** `true` once a new worker has installed and is waiting to activate. */\n updateAvailable: boolean;\n /**\n * Activate the waiting worker and reload the page once it takes control.\n * No-op when no update is waiting.\n */\n applyUpdate: () => void;\n /** The active registration, or `null` before it resolves / when unsupported. */\n registration: ServiceWorkerRegistration | null;\n}\n\n/**\n * Register a service worker and expose a user-driven update flow.\n *\n * Wraps {@link registerServiceWorker}: when a fresh worker finishes installing\n * while the page is still controlled by the old one, `updateAvailable` flips to\n * `true`. Call `applyUpdate` — typically from an \"atualizar\" toast — to tell the\n * waiting worker to activate and reload the page once it takes control.\n *\n * Skips cleanly when the runtime has no service-worker support (`registration`\n * stays `null`, `updateAvailable` stays `false`).\n *\n * @param options - Registration options (`url` required); `autoUpdate` should\n * stay off so the reload is user-confirmed.\n * @returns The update state and `applyUpdate` action.\n *\n * @example\n * const { updateAvailable, applyUpdate } = useServiceWorkerUpdate({ url: \"/sw.js\" });\n * return (\n * <UpdatePrompt open={updateAvailable} onUpdate={applyUpdate} />\n * );\n */\nexport function useServiceWorkerUpdate(\n options: UseServiceWorkerUpdateOptions,\n): UseServiceWorkerUpdateResult {\n const [updateAvailable, setUpdateAvailable] = useState<boolean>(false);\n const [registration, setRegistration] = useState<ServiceWorkerRegistration | null>(null);\n const waitingRef = useRef<ServiceWorker | null>(null);\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n useEffect(() => {\n let cancelled = false;\n void registerServiceWorker({\n ...optionsRef.current,\n onUpdate: (waiting, reg) => {\n waitingRef.current = waiting;\n setRegistration(reg);\n setUpdateAvailable(true);\n },\n onReady: (reg) => {\n if (cancelled) return;\n setRegistration(reg);\n if (reg.waiting && navigator.serviceWorker.controller) {\n waitingRef.current = reg.waiting;\n setUpdateAvailable(true);\n }\n optionsRef.current.onReady?.(reg);\n },\n }).then((reg) => {\n if (!cancelled && reg) setRegistration(reg);\n });\n return () => {\n cancelled = true;\n };\n }, [options.url]);\n\n const applyUpdate = useCallback(() => {\n const waiting = waitingRef.current;\n if (!waiting || typeof navigator === \"undefined\") return;\n let reloading = false;\n navigator.serviceWorker.addEventListener(\"controllerchange\", () => {\n if (reloading) return;\n reloading = true;\n window.location.reload();\n });\n skipWaiting(waiting);\n }, []);\n\n return { updateAvailable, applyUpdate, registration };\n}\n"],"mappings":";;;AAmDA,SAAgB,EACZ,GAC4B;CAC5B,IAAM,CAAC,GAAiB,KAAsB,EAAkB,EAAK,GAC/D,CAAC,GAAc,KAAmB,EAA2C,IAAI,GACjF,IAAa,EAA6B,IAAI,GAE9C,IAAa,EAAO,CAAO;CAyCjC,OAxCA,EAAW,UAAU,GAErB,QAAgB;EACZ,IAAI,IAAY;EAoBhB,OAnBA,EAA2B;GACvB,GAAG,EAAW;GACd,WAAW,GAAS,MAAQ;IAGxB,AAFA,EAAW,UAAU,GACrB,EAAgB,CAAG,GACnB,EAAmB,EAAI;GAC3B;GACA,UAAU,MAAQ;IACV,MACJ,EAAgB,CAAG,GACf,EAAI,WAAW,UAAU,cAAc,eACvC,EAAW,UAAU,EAAI,SACzB,EAAmB,EAAI,IAE3B,EAAW,QAAQ,UAAU,CAAG;GACpC;EACJ,CAAC,CAAC,CAAC,MAAM,MAAQ;GACb,AAAI,CAAC,KAAa,KAAK,EAAgB,CAAG;EAC9C,CAAC,SACY;GACT,IAAY;EAChB;CACJ,GAAG,CAAC,EAAQ,GAAG,CAAC,GAcT;EAAE;EAAiB,aAZN,QAAkB;GAClC,IAAM,IAAU,EAAW;GAC3B,IAAI,CAAC,KAAW,OAAO,YAAc,KAAa;GAClD,IAAI,IAAY;GAMhB,AALA,UAAU,cAAc,iBAAiB,0BAA0B;IAC3D,MACJ,IAAY,IACZ,OAAO,SAAS,OAAO;GAC3B,CAAC,GACD,EAAY,CAAO;EACvB,GAAG,CAAC,CAEsB;EAAa;CAAa;AACxD"}
1
+ {"version":3,"file":"use-service-worker-update.js","names":[],"sources":["../../src/hooks/use-service-worker-update.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n registerServiceWorker,\n skipWaiting,\n type RegisterServiceWorkerOptions,\n} from \"../sw/register-service-worker\";\n\n/**\n * Options for {@link useServiceWorkerUpdate}. Mirrors the registration options\n * minus the callbacks the hook owns internally (`onUpdate`); `onReady` and\n * `onError` still pass through for host-side logging.\n *\n * Leave `autoUpdate` off (the default): this hook exists to hand the reload\n * decision to the user, so a silent auto-reload would defeat the prompt.\n */\nexport type UseServiceWorkerUpdateOptions = Omit<RegisterServiceWorkerOptions, \"onUpdate\">;\n\n/** Reactive service-worker update state plus the apply action. */\nexport interface UseServiceWorkerUpdateResult {\n /** `true` once a new worker has installed and is waiting to activate. */\n updateAvailable: boolean;\n /**\n * Activate the waiting worker and reload the page once it takes control.\n * No-op when no update is waiting.\n */\n applyUpdate: () => void;\n /** The active registration, or `null` before it resolves / when unsupported. */\n registration: ServiceWorkerRegistration | null;\n}\n\n/**\n * Register a service worker and expose a user-driven update flow.\n *\n * Wraps {@link registerServiceWorker}: when a fresh worker finishes installing\n * while the page is still controlled by the old one, `updateAvailable` flips to\n * `true`. Call `applyUpdate` — typically from an \"atualizar\" toast — to tell the\n * waiting worker to activate and reload the page once it takes control.\n *\n * Skips cleanly when the runtime has no service-worker support (`registration`\n * stays `null`, `updateAvailable` stays `false`).\n *\n * @param options - Registration options (`url` required); `autoUpdate` should\n * stay off so the reload is user-confirmed.\n * @returns The update state and `applyUpdate` action.\n *\n * @example\n * const { updateAvailable, applyUpdate } = useServiceWorkerUpdate({ url: \"/sw.js\" });\n * return (\n * <UpdatePrompt open={updateAvailable} onUpdate={applyUpdate} />\n * );\n */\nexport function useServiceWorkerUpdate(\n options: UseServiceWorkerUpdateOptions,\n): UseServiceWorkerUpdateResult {\n const [updateAvailable, setUpdateAvailable] = useState<boolean>(false);\n const [registration, setRegistration] = useState<ServiceWorkerRegistration | null>(null);\n const waitingRef = useRef<ServiceWorker | null>(null);\n\n const optionsRef = useRef(options);\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n useEffect(() => {\n let cancelled = false;\n void registerServiceWorker({\n ...optionsRef.current,\n onUpdate: (waiting, reg) => {\n waitingRef.current = waiting;\n setRegistration(reg);\n setUpdateAvailable(true);\n },\n onReady: (reg) => {\n if (cancelled) return;\n setRegistration(reg);\n if (reg.waiting && navigator.serviceWorker.controller) {\n waitingRef.current = reg.waiting;\n setUpdateAvailable(true);\n }\n optionsRef.current.onReady?.(reg);\n },\n }).then((reg) => {\n if (!cancelled && reg) setRegistration(reg);\n });\n return () => {\n cancelled = true;\n };\n }, [options.url]);\n\n const applyUpdate = useCallback(() => {\n const waiting = waitingRef.current;\n if (!waiting || typeof navigator === \"undefined\") return;\n let reloading = false;\n navigator.serviceWorker.addEventListener(\"controllerchange\", () => {\n if (reloading) return;\n reloading = true;\n window.location.reload();\n });\n skipWaiting(waiting);\n }, []);\n\n return { updateAvailable, applyUpdate, registration };\n}\n"],"mappings":";;;AAmDA,SAAgB,EACZ,GAC4B;CAC5B,IAAM,CAAC,GAAiB,KAAsB,EAAkB,EAAK,GAC/D,CAAC,GAAc,KAAmB,EAA2C,IAAI,GACjF,IAAa,EAA6B,IAAI,GAE9C,IAAa,EAAO,CAAO;CA2CjC,OA1CA,QAAgB;EACZ,EAAW,UAAU;CACzB,GAAG,CAAC,CAAO,CAAC,GAEZ,QAAgB;EACZ,IAAI,IAAY;EAoBhB,OAnBA,EAA2B;GACvB,GAAG,EAAW;GACd,WAAW,GAAS,MAAQ;IAGxB,AAFA,EAAW,UAAU,GACrB,EAAgB,CAAG,GACnB,EAAmB,EAAI;GAC3B;GACA,UAAU,MAAQ;IACV,MACJ,EAAgB,CAAG,GACf,EAAI,WAAW,UAAU,cAAc,eACvC,EAAW,UAAU,EAAI,SACzB,EAAmB,EAAI,IAE3B,EAAW,QAAQ,UAAU,CAAG;GACpC;EACJ,CAAC,CAAC,CAAC,MAAM,MAAQ;GACb,AAAI,CAAC,KAAa,KAAK,EAAgB,CAAG;EAC9C,CAAC,SACY;GACT,IAAY;EAChB;CACJ,GAAG,CAAC,EAAQ,GAAG,CAAC,GAcT;EAAE;EAAiB,aAZN,QAAkB;GAClC,IAAM,IAAU,EAAW;GAC3B,IAAI,CAAC,KAAW,OAAO,YAAc,KAAa;GAClD,IAAI,IAAY;GAMhB,AALA,UAAU,cAAc,iBAAiB,0BAA0B;IAC3D,MACJ,IAAY,IACZ,OAAO,SAAS,OAAO;GAC3B,CAAC,GACD,EAAY,CAAO;EACvB,GAAG,CAAC,CAEsB;EAAa;CAAa;AACxD"}
@@ -0,0 +1,2 @@
1
+ let e=require("react");function t(e,t,n){if(t===n||t<0||n<0||t>=e.length||n>=e.length)return e;let r=e.slice(),[i]=r.splice(t,1);return r.splice(n,0,i),r}function n(e,t,n){if(!e)return null;let r=e=>{let r=e.getBoundingClientRect();return n>=r.top&&n<=r.bottom&&t>=r.left&&t<=r.right};for(let t of Array.from(e.querySelectorAll(`[data-sortable-index]`))){if(!r(t))continue;let e=Number(t.dataset.sortableIndex);return Number.isNaN(e)?null:{index:e,group:t.dataset.sortableGroup}}for(let t of Array.from(e.querySelectorAll(`[data-sortable-empty]`)))if(r(t))return{index:0,group:t.dataset.sortableGroup};return null}function r(t){let{itemCount:r,onReorder:i,disabled:a=!1,roleDescription:o=`Sortable item`}=t,[s,c]=(0,e.useState)(null),[l,u]=(0,e.useState)(null),d=(0,e.useRef)(null),f=(0,e.useRef)(i),p=(0,e.useRef)(null),m=(0,e.useRef)(null),[h,g]=(0,e.useState)(void 0),[_,v]=(0,e.useState)(void 0),y=(0,e.useRef)(void 0),b=(0,e.useRef)(void 0),x=(0,e.useCallback)(e=>{y.current=e,g(e)},[]),S=(0,e.useCallback)(e=>{b.current=e,v(e)},[]),C=(0,e.useCallback)(e=>{p.current=e,c(e)},[]),w=(0,e.useCallback)(e=>{m.current=e,u(e)},[]);(0,e.useEffect)(()=>{f.current=i},[i]);let T=(0,e.useCallback)(()=>{x(void 0),S(void 0),C(null),w(null)},[x,C,S,w]);(0,e.useEffect)(()=>{T()},[r,T]);let E=(0,e.useCallback)((e,t,n,r)=>{(e!==t||n!==r)&&f.current({from:e,to:t,fromGroup:n,toGroup:r}),T()},[T]),D=(0,e.useCallback)(e=>{d.current=e},[]),O=(0,e.useCallback)((e,t,n)=>{a||(n.currentTarget.setPointerCapture?.(n.pointerId),x(t),S(t),C(e),w(e))},[a,x,C,S,w]);(0,e.useEffect)(()=>{if(s===null)return;function e(e){let t=n(d.current,e.clientX,e.clientY);t&&(S(t.group),w(t.index))}function t(){let e=p.current,t=m.current;e!==null&&t!==null?E(e,t,y.current,b.current):T()}function r(e){e.key===`Escape`&&T()}return window.addEventListener(`pointermove`,e),window.addEventListener(`pointerup`,t),window.addEventListener(`pointercancel`,T),window.addEventListener(`keydown`,r),()=>{window.removeEventListener(`pointermove`,e),window.removeEventListener(`pointerup`,t),window.removeEventListener(`pointercancel`,T),window.removeEventListener(`keydown`,r)}},[s,E,T,S,w]);let k=(0,e.useCallback)((e,t,n)=>{if(a)return;let i=s!==null;switch(n.key){case` `:case`Enter`:n.preventDefault(),i?l!==null&&E(s,l,h,_):(x(t),S(t),C(e),w(e));break;case`ArrowDown`:case`ArrowRight`:if(!i)return;n.preventDefault(),m.current!==null&&w(Math.min(m.current+1,r-1));break;case`ArrowUp`:case`ArrowLeft`:if(!i)return;n.preventDefault(),m.current!==null&&w(Math.max(m.current-1,0));break;case`Escape`:if(!i)return;n.preventDefault(),T();break;default:break}},[h,s,E,_,a,r,l,T,x,C,S,w]);return{activeIndex:s,overIndex:l,activeGroup:h,overGroup:_,getItemProps:(0,e.useCallback)((e,t)=>({"data-sortable-index":e,"data-sortable-group":t,"data-sortable-active":s===e&&h===t||void 0,onPointerDown:n=>O(e,t,n),onKeyDown:n=>k(e,t,n),tabIndex:a?-1:0,role:`option`,"aria-roledescription":o,"aria-selected":s===e&&h===t}),[h,s,a,k,O,o]),getEmptyGroupProps:(0,e.useCallback)(e=>({"data-sortable-group":e,"data-sortable-empty":!0}),[]),getListProps:(0,e.useCallback)(()=>({role:`listbox`,"aria-orientation":`vertical`}),[]),cancel:T,setContainer:D}}exports.moveItem=t,exports.useSortable=r;
2
+ //# sourceMappingURL=use-sortable.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-sortable.cjs","names":[],"sources":["../../src/hooks/use-sortable.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { KeyboardEvent as ReactKeyboardEvent, PointerEvent as ReactPointerEvent } from \"react\";\n\n/** Where a dragged item would land if dropped now. */\nexport interface SortableDropTarget {\n /** Index the item started at, within its own group. */\n from: number;\n /** Index it would move to, within the destination group. */\n to: number;\n /**\n * Group the item started in — a Kanban column, for instance. `undefined` for a\n * plain single-list sortable.\n */\n fromGroup?: string;\n /** Destination group. Equal to `fromGroup` when the move stays in one group. */\n toGroup?: string;\n}\n\n/** Props to spread on each sortable item. */\nexport interface SortableItemProps {\n /** Marks the item for hit-testing. */\n \"data-sortable-index\": number;\n /** Group the item belongs to, when the sortable spans several lists. */\n \"data-sortable-group\"?: string;\n /** `true` while this item is the one being moved. */\n \"data-sortable-active\"?: boolean;\n /** Grab handle wiring: starts a pointer drag. */\n onPointerDown: (event: ReactPointerEvent<HTMLElement>) => void;\n /** Keyboard reordering — see {@link UseSortableResult}. */\n onKeyDown: (event: ReactKeyboardEvent<HTMLElement>) => void;\n /** Puts the item in the tab order so the keyboard path is reachable. */\n tabIndex: number;\n role: \"option\";\n \"aria-roledescription\": string;\n \"aria-selected\": boolean;\n}\n\nexport interface UseSortableOptions {\n /**\n * How many items are in the sortable. Changing it cancels an in-flight drag.\n *\n * With groups, pass the **total** across groups: the number only has to change\n * whenever the indices the drag was based on stop being valid.\n */\n itemCount: number;\n /**\n * Called once, when a move is committed — on pointer release or on a keyboard\n * move. Never called mid-drag, so a controlled list re-renders once instead of\n * on every pointer frame.\n */\n onReorder: (target: SortableDropTarget) => void;\n /** Blocks all interaction. */\n disabled?: boolean;\n /**\n * Description announced for each item, so a screen reader user learns the\n * keyboard contract. Default is in English — override it to localize.\n */\n roleDescription?: string;\n}\n\nexport interface UseSortableResult {\n /** Index being dragged, or `null` when idle. */\n activeIndex: number | null;\n /** Index the item would land on, or `null` when idle. */\n overIndex: number | null;\n /** Group the dragged item came from, when using groups. */\n activeGroup?: string;\n /** Group the item is currently over, when using groups. */\n overGroup?: string;\n /**\n * Spread on each item. Pass `group` when the sortable spans several lists (a\n * Kanban column id), so a drop can land in a different group.\n */\n getItemProps: (index: number, group?: string) => SortableItemProps;\n /**\n * Spread on an **empty** group's drop area, so an item can be moved into a\n * column that has no cards yet — hit-testing works off item rects, and a group\n * with no items has none.\n */\n getEmptyGroupProps: (group: string) => {\n \"data-sortable-group\": string;\n \"data-sortable-empty\": true;\n };\n /** Spread on the list container (`role=\"listbox\"` + a label of your own). */\n getListProps: () => { role: \"listbox\"; \"aria-orientation\": \"vertical\" };\n /** Abort the current drag without reordering. */\n cancel: () => void;\n /**\n * Callback ref for the element that contains the sortable items — hit-testing\n * searches inside it.\n *\n * Named `setContainer` rather than `ref` because it is a **callback**, not a ref\n * object: `ref={sortable.setContainer}`. The old name also read as a readable\n * ref to the React Compiler rules, which flagged every consumer.\n */\n setContainer: (node: HTMLElement | null) => void;\n}\n\n/** Reorder helper: move `from` to `to`, returning a new array. */\nexport function moveItem<T>(items: T[], from: number, to: number): T[] {\n if (from === to || from < 0 || to < 0 || from >= items.length || to >= items.length) {\n return items;\n }\n const next = items.slice();\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved);\n return next;\n}\n\n/** A hit-test result: the item (or empty group) under the pointer. */\ninterface HitTarget {\n index: number;\n group?: string;\n}\n\n/**\n * Find the sortable slot under a viewport point.\n *\n * Items are tried first; an empty group's drop area is only considered when no item\n * matched, since an empty column is a fallback target rather than a competing one.\n */\nfunction targetAtPoint(container: HTMLElement | null, x: number, y: number): HitTarget | null {\n if (!container) return null;\n const inside = (element: HTMLElement): boolean => {\n const rect = element.getBoundingClientRect();\n return y >= rect.top && y <= rect.bottom && x >= rect.left && x <= rect.right;\n };\n\n for (const item of Array.from(\n container.querySelectorAll<HTMLElement>(\"[data-sortable-index]\"),\n )) {\n if (!inside(item)) continue;\n const index = Number(item.dataset.sortableIndex);\n if (Number.isNaN(index)) return null;\n return { index, group: item.dataset.sortableGroup };\n }\n\n for (const empty of Array.from(\n container.querySelectorAll<HTMLElement>(\"[data-sortable-empty]\"),\n )) {\n if (inside(empty)) return { index: 0, group: empty.dataset.sortableGroup };\n }\n\n return null;\n}\n\n/**\n * Drag-to-reorder for a list, with a **keyboard path of equal standing**.\n *\n * Pointer events cover mouse, touch and stylus through one code path, and pointer\n * capture keeps the drag alive when the pointer leaves the item. `Space` picks an\n * item up, the arrows move it, `Space`/`Enter` drops it and `Escape` cancels —\n * because a reorder that only works by dragging excludes keyboard users\n * completely, which is where most drag-and-drop implementations fail.\n *\n * The hook owns interaction only: it never mutates your data. `onReorder` fires\n * once per committed move and you apply it, typically with {@link moveItem}. That\n * keeps the list a controlled value and avoids a re-render per pointer frame.\n *\n * Hit-testing reads the live DOM rects of `[data-sortable-index]` children rather\n * than assuming a fixed row height, so it works with rows of different sizes.\n *\n * A change in `itemCount` cancels an in-flight drag: the list no longer has the\n * indices the drag was based on, and committing anyway would move the wrong row.\n *\n * Note for consumers: the indices and groups are exposed as **state** (so rendering\n * from them is reactive) and mirrored into refs only so the window-level `pointerup`\n * listener can read both synchronously. Because the handlers returned by\n * `getItemProps` close over those mirrors, the React Compiler `refs` rule reports\n * the *call site* — a component spreading these props may need a file-level\n * exemption, as `Kanban` documents.\n *\n * @example\n * ```tsx\n * const [items, setItems] = useState([\"Alfa\", \"Bravo\", \"Charlie\"]);\n * const sortable = useSortable({\n * itemCount: items.length,\n * onReorder: ({ from, to }) => setItems((current) => moveItem(current, from, to)),\n * });\n *\n * <ul {...sortable.getListProps()} aria-label=\"Prioridade\" ref={sortable.setContainer}>\n * {items.map((item, index) => (\n * <li key={item} {...sortable.getItemProps(index)}>\n * {item}\n * </li>\n * ))}\n * </ul>\n * ```\n */\nexport function useSortable(options: UseSortableOptions): UseSortableResult {\n const { itemCount, onReorder, disabled = false, roleDescription = \"Sortable item\" } = options;\n\n const [activeIndex, setActiveIndexState] = useState<number | null>(null);\n const [overIndex, setOverIndexState] = useState<number | null>(null);\n const containerRef = useRef<HTMLElement | null>(null);\n const onReorderRef = useRef(onReorder);\n\n /**\n * Mirrors of the two indices.\n *\n * The window-level `pointerup` listener has to read both values *synchronously*\n * to know what to commit, and a state setter only exposes one of them. Mirroring\n * into refs keeps the commit readable instead of nesting setters to smuggle the\n * other value out.\n */\n const activeRef = useRef<number | null>(null);\n const overRef = useRef<number | null>(null);\n const [activeGroup, setActiveGroupState] = useState<string | undefined>(undefined);\n const [overGroup, setOverGroupState] = useState<string | undefined>(undefined);\n const activeGroupRef = useRef<string | undefined>(undefined);\n const overGroupRef = useRef<string | undefined>(undefined);\n\n const setActiveGroup = useCallback((value: string | undefined): void => {\n activeGroupRef.current = value;\n setActiveGroupState(value);\n }, []);\n\n const setOverGroup = useCallback((value: string | undefined): void => {\n overGroupRef.current = value;\n setOverGroupState(value);\n }, []);\n\n const setActiveIndex = useCallback((value: number | null): void => {\n activeRef.current = value;\n setActiveIndexState(value);\n }, []);\n\n const setOverIndex = useCallback((value: number | null): void => {\n overRef.current = value;\n setOverIndexState(value);\n }, []);\n\n useEffect(() => {\n onReorderRef.current = onReorder;\n }, [onReorder]);\n\n const reset = useCallback((): void => {\n setActiveGroup(undefined);\n setOverGroup(undefined);\n setActiveIndex(null);\n setOverIndex(null);\n }, [setActiveGroup, setActiveIndex, setOverGroup, setOverIndex]);\n\n useEffect(() => {\n reset();\n }, [itemCount, reset]);\n\n /**\n * Report a committed move and go back to idle.\n *\n * The groups are **arguments**, not reads of the mirror refs: `commit` ends up\n * inside the props returned by `getItemProps`, which render calls, and a ref read\n * anywhere in that closure chain is a render-time ref access. The pointer\n * listener reads the mirrors itself — it is an event handler, where reading is\n * fine — and hands the values over.\n *\n * A move that changes group counts even at the same index (the card lands in\n * another column), so only a same-group, same-index drop is \"nothing happened\".\n */\n const commit = useCallback(\n (from: number, to: number, fromGroup?: string, toGroup?: string): void => {\n if (from !== to || fromGroup !== toGroup) {\n onReorderRef.current({ from, to, fromGroup, toGroup });\n }\n reset();\n },\n [reset],\n );\n\n const setContainer = useCallback((node: HTMLElement | null): void => {\n containerRef.current = node;\n }, []);\n\n const handlePointerDown = useCallback(\n (index: number, group: string | undefined, event: ReactPointerEvent<HTMLElement>): void => {\n if (disabled) return;\n event.currentTarget.setPointerCapture?.(event.pointerId);\n setActiveGroup(group);\n setOverGroup(group);\n setActiveIndex(index);\n setOverIndex(index);\n },\n [disabled, setActiveGroup, setActiveIndex, setOverGroup, setOverIndex],\n );\n\n useEffect(() => {\n if (activeIndex === null) return;\n\n function onPointerMove(event: PointerEvent): void {\n const target = targetAtPoint(containerRef.current, event.clientX, event.clientY);\n if (!target) return;\n setOverGroup(target.group);\n setOverIndex(target.index);\n }\n\n function onPointerUp(): void {\n const from = activeRef.current;\n const to = overRef.current;\n if (from !== null && to !== null) {\n commit(from, to, activeGroupRef.current, overGroupRef.current);\n } else {\n reset();\n }\n }\n\n function onKeyDown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") reset();\n }\n\n window.addEventListener(\"pointermove\", onPointerMove);\n window.addEventListener(\"pointerup\", onPointerUp);\n window.addEventListener(\"pointercancel\", reset);\n window.addEventListener(\"keydown\", onKeyDown);\n return () => {\n window.removeEventListener(\"pointermove\", onPointerMove);\n window.removeEventListener(\"pointerup\", onPointerUp);\n window.removeEventListener(\"pointercancel\", reset);\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [activeIndex, commit, reset, setOverGroup, setOverIndex]);\n\n const handleKeyDown = useCallback(\n (\n index: number,\n group: string | undefined,\n event: ReactKeyboardEvent<HTMLElement>,\n ): void => {\n if (disabled) return;\n const picked = activeIndex !== null;\n\n switch (event.key) {\n case \" \":\n case \"Enter\":\n event.preventDefault();\n if (!picked) {\n setActiveGroup(group);\n setOverGroup(group);\n setActiveIndex(index);\n setOverIndex(index);\n } else if (overIndex !== null) {\n commit(activeIndex, overIndex, activeGroup, overGroup);\n }\n break;\n case \"ArrowDown\":\n case \"ArrowRight\": {\n if (!picked) return;\n event.preventDefault();\n if (overRef.current !== null) {\n setOverIndex(Math.min(overRef.current + 1, itemCount - 1));\n }\n break;\n }\n case \"ArrowUp\":\n case \"ArrowLeft\": {\n if (!picked) return;\n event.preventDefault();\n if (overRef.current !== null) {\n setOverIndex(Math.max(overRef.current - 1, 0));\n }\n break;\n }\n case \"Escape\":\n if (!picked) return;\n event.preventDefault();\n reset();\n break;\n default:\n break;\n }\n },\n [\n activeGroup,\n activeIndex,\n commit,\n overGroup,\n disabled,\n itemCount,\n overIndex,\n reset,\n setActiveGroup,\n setActiveIndex,\n setOverGroup,\n setOverIndex,\n ],\n );\n\n const getItemProps = useCallback(\n (index: number, group?: string): SortableItemProps => ({\n \"data-sortable-index\": index,\n \"data-sortable-group\": group,\n \"data-sortable-active\": (activeIndex === index && activeGroup === group) || undefined,\n onPointerDown: (event) => handlePointerDown(index, group, event),\n onKeyDown: (event) => handleKeyDown(index, group, event),\n tabIndex: disabled ? -1 : 0,\n role: \"option\",\n \"aria-roledescription\": roleDescription,\n \"aria-selected\": activeIndex === index && activeGroup === group,\n }),\n [activeGroup, activeIndex, disabled, handleKeyDown, handlePointerDown, roleDescription],\n );\n\n const getEmptyGroupProps = useCallback(\n (group: string) => ({ \"data-sortable-group\": group, \"data-sortable-empty\": true as const }),\n [],\n );\n\n const getListProps = useCallback(\n () => ({ role: \"listbox\" as const, \"aria-orientation\": \"vertical\" as const }),\n [],\n );\n\n return {\n activeIndex,\n overIndex,\n activeGroup,\n overGroup,\n getItemProps,\n getEmptyGroupProps,\n getListProps,\n cancel: reset,\n setContainer,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,169 @@
1
+ import { useCallback as e, useEffect as t, useRef as n, useState as r } from "react";
2
+ //#region src/hooks/use-sortable.ts
3
+ function i(e, t, n) {
4
+ if (t === n || t < 0 || n < 0 || t >= e.length || n >= e.length) return e;
5
+ let r = e.slice(), [i] = r.splice(t, 1);
6
+ return r.splice(n, 0, i), r;
7
+ }
8
+ function a(e, t, n) {
9
+ if (!e) return null;
10
+ let r = (e) => {
11
+ let r = e.getBoundingClientRect();
12
+ return n >= r.top && n <= r.bottom && t >= r.left && t <= r.right;
13
+ };
14
+ for (let t of Array.from(e.querySelectorAll("[data-sortable-index]"))) {
15
+ if (!r(t)) continue;
16
+ let e = Number(t.dataset.sortableIndex);
17
+ return Number.isNaN(e) ? null : {
18
+ index: e,
19
+ group: t.dataset.sortableGroup
20
+ };
21
+ }
22
+ for (let t of Array.from(e.querySelectorAll("[data-sortable-empty]"))) if (r(t)) return {
23
+ index: 0,
24
+ group: t.dataset.sortableGroup
25
+ };
26
+ return null;
27
+ }
28
+ function o(i) {
29
+ let { itemCount: o, onReorder: s, disabled: c = !1, roleDescription: l = "Sortable item" } = i, [u, d] = r(null), [f, p] = r(null), m = n(null), h = n(s), g = n(null), _ = n(null), [v, y] = r(void 0), [b, x] = r(void 0), S = n(void 0), C = n(void 0), w = e((e) => {
30
+ S.current = e, y(e);
31
+ }, []), T = e((e) => {
32
+ C.current = e, x(e);
33
+ }, []), E = e((e) => {
34
+ g.current = e, d(e);
35
+ }, []), D = e((e) => {
36
+ _.current = e, p(e);
37
+ }, []);
38
+ t(() => {
39
+ h.current = s;
40
+ }, [s]);
41
+ let O = e(() => {
42
+ w(void 0), T(void 0), E(null), D(null);
43
+ }, [
44
+ w,
45
+ E,
46
+ T,
47
+ D
48
+ ]);
49
+ t(() => {
50
+ O();
51
+ }, [o, O]);
52
+ let k = e((e, t, n, r) => {
53
+ (e !== t || n !== r) && h.current({
54
+ from: e,
55
+ to: t,
56
+ fromGroup: n,
57
+ toGroup: r
58
+ }), O();
59
+ }, [O]), A = e((e) => {
60
+ m.current = e;
61
+ }, []), j = e((e, t, n) => {
62
+ c || (n.currentTarget.setPointerCapture?.(n.pointerId), w(t), T(t), E(e), D(e));
63
+ }, [
64
+ c,
65
+ w,
66
+ E,
67
+ T,
68
+ D
69
+ ]);
70
+ t(() => {
71
+ if (u === null) return;
72
+ function e(e) {
73
+ let t = a(m.current, e.clientX, e.clientY);
74
+ t && (T(t.group), D(t.index));
75
+ }
76
+ function t() {
77
+ let e = g.current, t = _.current;
78
+ e !== null && t !== null ? k(e, t, S.current, C.current) : O();
79
+ }
80
+ function n(e) {
81
+ e.key === "Escape" && O();
82
+ }
83
+ return window.addEventListener("pointermove", e), window.addEventListener("pointerup", t), window.addEventListener("pointercancel", O), window.addEventListener("keydown", n), () => {
84
+ window.removeEventListener("pointermove", e), window.removeEventListener("pointerup", t), window.removeEventListener("pointercancel", O), window.removeEventListener("keydown", n);
85
+ };
86
+ }, [
87
+ u,
88
+ k,
89
+ O,
90
+ T,
91
+ D
92
+ ]);
93
+ let M = e((e, t, n) => {
94
+ if (c) return;
95
+ let r = u !== null;
96
+ switch (n.key) {
97
+ case " ":
98
+ case "Enter":
99
+ n.preventDefault(), r ? f !== null && k(u, f, v, b) : (w(t), T(t), E(e), D(e));
100
+ break;
101
+ case "ArrowDown":
102
+ case "ArrowRight":
103
+ if (!r) return;
104
+ n.preventDefault(), _.current !== null && D(Math.min(_.current + 1, o - 1));
105
+ break;
106
+ case "ArrowUp":
107
+ case "ArrowLeft":
108
+ if (!r) return;
109
+ n.preventDefault(), _.current !== null && D(Math.max(_.current - 1, 0));
110
+ break;
111
+ case "Escape":
112
+ if (!r) return;
113
+ n.preventDefault(), O();
114
+ break;
115
+ default: break;
116
+ }
117
+ }, [
118
+ v,
119
+ u,
120
+ k,
121
+ b,
122
+ c,
123
+ o,
124
+ f,
125
+ O,
126
+ w,
127
+ E,
128
+ T,
129
+ D
130
+ ]);
131
+ return {
132
+ activeIndex: u,
133
+ overIndex: f,
134
+ activeGroup: v,
135
+ overGroup: b,
136
+ getItemProps: e((e, t) => ({
137
+ "data-sortable-index": e,
138
+ "data-sortable-group": t,
139
+ "data-sortable-active": u === e && v === t || void 0,
140
+ onPointerDown: (n) => j(e, t, n),
141
+ onKeyDown: (n) => M(e, t, n),
142
+ tabIndex: c ? -1 : 0,
143
+ role: "option",
144
+ "aria-roledescription": l,
145
+ "aria-selected": u === e && v === t
146
+ }), [
147
+ v,
148
+ u,
149
+ c,
150
+ M,
151
+ j,
152
+ l
153
+ ]),
154
+ getEmptyGroupProps: e((e) => ({
155
+ "data-sortable-group": e,
156
+ "data-sortable-empty": !0
157
+ }), []),
158
+ getListProps: e(() => ({
159
+ role: "listbox",
160
+ "aria-orientation": "vertical"
161
+ }), []),
162
+ cancel: O,
163
+ setContainer: A
164
+ };
165
+ }
166
+ //#endregion
167
+ export { i as moveItem, o as useSortable };
168
+
169
+ //# sourceMappingURL=use-sortable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-sortable.js","names":[],"sources":["../../src/hooks/use-sortable.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { KeyboardEvent as ReactKeyboardEvent, PointerEvent as ReactPointerEvent } from \"react\";\n\n/** Where a dragged item would land if dropped now. */\nexport interface SortableDropTarget {\n /** Index the item started at, within its own group. */\n from: number;\n /** Index it would move to, within the destination group. */\n to: number;\n /**\n * Group the item started in — a Kanban column, for instance. `undefined` for a\n * plain single-list sortable.\n */\n fromGroup?: string;\n /** Destination group. Equal to `fromGroup` when the move stays in one group. */\n toGroup?: string;\n}\n\n/** Props to spread on each sortable item. */\nexport interface SortableItemProps {\n /** Marks the item for hit-testing. */\n \"data-sortable-index\": number;\n /** Group the item belongs to, when the sortable spans several lists. */\n \"data-sortable-group\"?: string;\n /** `true` while this item is the one being moved. */\n \"data-sortable-active\"?: boolean;\n /** Grab handle wiring: starts a pointer drag. */\n onPointerDown: (event: ReactPointerEvent<HTMLElement>) => void;\n /** Keyboard reordering — see {@link UseSortableResult}. */\n onKeyDown: (event: ReactKeyboardEvent<HTMLElement>) => void;\n /** Puts the item in the tab order so the keyboard path is reachable. */\n tabIndex: number;\n role: \"option\";\n \"aria-roledescription\": string;\n \"aria-selected\": boolean;\n}\n\nexport interface UseSortableOptions {\n /**\n * How many items are in the sortable. Changing it cancels an in-flight drag.\n *\n * With groups, pass the **total** across groups: the number only has to change\n * whenever the indices the drag was based on stop being valid.\n */\n itemCount: number;\n /**\n * Called once, when a move is committed — on pointer release or on a keyboard\n * move. Never called mid-drag, so a controlled list re-renders once instead of\n * on every pointer frame.\n */\n onReorder: (target: SortableDropTarget) => void;\n /** Blocks all interaction. */\n disabled?: boolean;\n /**\n * Description announced for each item, so a screen reader user learns the\n * keyboard contract. Default is in English — override it to localize.\n */\n roleDescription?: string;\n}\n\nexport interface UseSortableResult {\n /** Index being dragged, or `null` when idle. */\n activeIndex: number | null;\n /** Index the item would land on, or `null` when idle. */\n overIndex: number | null;\n /** Group the dragged item came from, when using groups. */\n activeGroup?: string;\n /** Group the item is currently over, when using groups. */\n overGroup?: string;\n /**\n * Spread on each item. Pass `group` when the sortable spans several lists (a\n * Kanban column id), so a drop can land in a different group.\n */\n getItemProps: (index: number, group?: string) => SortableItemProps;\n /**\n * Spread on an **empty** group's drop area, so an item can be moved into a\n * column that has no cards yet — hit-testing works off item rects, and a group\n * with no items has none.\n */\n getEmptyGroupProps: (group: string) => {\n \"data-sortable-group\": string;\n \"data-sortable-empty\": true;\n };\n /** Spread on the list container (`role=\"listbox\"` + a label of your own). */\n getListProps: () => { role: \"listbox\"; \"aria-orientation\": \"vertical\" };\n /** Abort the current drag without reordering. */\n cancel: () => void;\n /**\n * Callback ref for the element that contains the sortable items — hit-testing\n * searches inside it.\n *\n * Named `setContainer` rather than `ref` because it is a **callback**, not a ref\n * object: `ref={sortable.setContainer}`. The old name also read as a readable\n * ref to the React Compiler rules, which flagged every consumer.\n */\n setContainer: (node: HTMLElement | null) => void;\n}\n\n/** Reorder helper: move `from` to `to`, returning a new array. */\nexport function moveItem<T>(items: T[], from: number, to: number): T[] {\n if (from === to || from < 0 || to < 0 || from >= items.length || to >= items.length) {\n return items;\n }\n const next = items.slice();\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved);\n return next;\n}\n\n/** A hit-test result: the item (or empty group) under the pointer. */\ninterface HitTarget {\n index: number;\n group?: string;\n}\n\n/**\n * Find the sortable slot under a viewport point.\n *\n * Items are tried first; an empty group's drop area is only considered when no item\n * matched, since an empty column is a fallback target rather than a competing one.\n */\nfunction targetAtPoint(container: HTMLElement | null, x: number, y: number): HitTarget | null {\n if (!container) return null;\n const inside = (element: HTMLElement): boolean => {\n const rect = element.getBoundingClientRect();\n return y >= rect.top && y <= rect.bottom && x >= rect.left && x <= rect.right;\n };\n\n for (const item of Array.from(\n container.querySelectorAll<HTMLElement>(\"[data-sortable-index]\"),\n )) {\n if (!inside(item)) continue;\n const index = Number(item.dataset.sortableIndex);\n if (Number.isNaN(index)) return null;\n return { index, group: item.dataset.sortableGroup };\n }\n\n for (const empty of Array.from(\n container.querySelectorAll<HTMLElement>(\"[data-sortable-empty]\"),\n )) {\n if (inside(empty)) return { index: 0, group: empty.dataset.sortableGroup };\n }\n\n return null;\n}\n\n/**\n * Drag-to-reorder for a list, with a **keyboard path of equal standing**.\n *\n * Pointer events cover mouse, touch and stylus through one code path, and pointer\n * capture keeps the drag alive when the pointer leaves the item. `Space` picks an\n * item up, the arrows move it, `Space`/`Enter` drops it and `Escape` cancels —\n * because a reorder that only works by dragging excludes keyboard users\n * completely, which is where most drag-and-drop implementations fail.\n *\n * The hook owns interaction only: it never mutates your data. `onReorder` fires\n * once per committed move and you apply it, typically with {@link moveItem}. That\n * keeps the list a controlled value and avoids a re-render per pointer frame.\n *\n * Hit-testing reads the live DOM rects of `[data-sortable-index]` children rather\n * than assuming a fixed row height, so it works with rows of different sizes.\n *\n * A change in `itemCount` cancels an in-flight drag: the list no longer has the\n * indices the drag was based on, and committing anyway would move the wrong row.\n *\n * Note for consumers: the indices and groups are exposed as **state** (so rendering\n * from them is reactive) and mirrored into refs only so the window-level `pointerup`\n * listener can read both synchronously. Because the handlers returned by\n * `getItemProps` close over those mirrors, the React Compiler `refs` rule reports\n * the *call site* — a component spreading these props may need a file-level\n * exemption, as `Kanban` documents.\n *\n * @example\n * ```tsx\n * const [items, setItems] = useState([\"Alfa\", \"Bravo\", \"Charlie\"]);\n * const sortable = useSortable({\n * itemCount: items.length,\n * onReorder: ({ from, to }) => setItems((current) => moveItem(current, from, to)),\n * });\n *\n * <ul {...sortable.getListProps()} aria-label=\"Prioridade\" ref={sortable.setContainer}>\n * {items.map((item, index) => (\n * <li key={item} {...sortable.getItemProps(index)}>\n * {item}\n * </li>\n * ))}\n * </ul>\n * ```\n */\nexport function useSortable(options: UseSortableOptions): UseSortableResult {\n const { itemCount, onReorder, disabled = false, roleDescription = \"Sortable item\" } = options;\n\n const [activeIndex, setActiveIndexState] = useState<number | null>(null);\n const [overIndex, setOverIndexState] = useState<number | null>(null);\n const containerRef = useRef<HTMLElement | null>(null);\n const onReorderRef = useRef(onReorder);\n\n /**\n * Mirrors of the two indices.\n *\n * The window-level `pointerup` listener has to read both values *synchronously*\n * to know what to commit, and a state setter only exposes one of them. Mirroring\n * into refs keeps the commit readable instead of nesting setters to smuggle the\n * other value out.\n */\n const activeRef = useRef<number | null>(null);\n const overRef = useRef<number | null>(null);\n const [activeGroup, setActiveGroupState] = useState<string | undefined>(undefined);\n const [overGroup, setOverGroupState] = useState<string | undefined>(undefined);\n const activeGroupRef = useRef<string | undefined>(undefined);\n const overGroupRef = useRef<string | undefined>(undefined);\n\n const setActiveGroup = useCallback((value: string | undefined): void => {\n activeGroupRef.current = value;\n setActiveGroupState(value);\n }, []);\n\n const setOverGroup = useCallback((value: string | undefined): void => {\n overGroupRef.current = value;\n setOverGroupState(value);\n }, []);\n\n const setActiveIndex = useCallback((value: number | null): void => {\n activeRef.current = value;\n setActiveIndexState(value);\n }, []);\n\n const setOverIndex = useCallback((value: number | null): void => {\n overRef.current = value;\n setOverIndexState(value);\n }, []);\n\n useEffect(() => {\n onReorderRef.current = onReorder;\n }, [onReorder]);\n\n const reset = useCallback((): void => {\n setActiveGroup(undefined);\n setOverGroup(undefined);\n setActiveIndex(null);\n setOverIndex(null);\n }, [setActiveGroup, setActiveIndex, setOverGroup, setOverIndex]);\n\n useEffect(() => {\n reset();\n }, [itemCount, reset]);\n\n /**\n * Report a committed move and go back to idle.\n *\n * The groups are **arguments**, not reads of the mirror refs: `commit` ends up\n * inside the props returned by `getItemProps`, which render calls, and a ref read\n * anywhere in that closure chain is a render-time ref access. The pointer\n * listener reads the mirrors itself — it is an event handler, where reading is\n * fine — and hands the values over.\n *\n * A move that changes group counts even at the same index (the card lands in\n * another column), so only a same-group, same-index drop is \"nothing happened\".\n */\n const commit = useCallback(\n (from: number, to: number, fromGroup?: string, toGroup?: string): void => {\n if (from !== to || fromGroup !== toGroup) {\n onReorderRef.current({ from, to, fromGroup, toGroup });\n }\n reset();\n },\n [reset],\n );\n\n const setContainer = useCallback((node: HTMLElement | null): void => {\n containerRef.current = node;\n }, []);\n\n const handlePointerDown = useCallback(\n (index: number, group: string | undefined, event: ReactPointerEvent<HTMLElement>): void => {\n if (disabled) return;\n event.currentTarget.setPointerCapture?.(event.pointerId);\n setActiveGroup(group);\n setOverGroup(group);\n setActiveIndex(index);\n setOverIndex(index);\n },\n [disabled, setActiveGroup, setActiveIndex, setOverGroup, setOverIndex],\n );\n\n useEffect(() => {\n if (activeIndex === null) return;\n\n function onPointerMove(event: PointerEvent): void {\n const target = targetAtPoint(containerRef.current, event.clientX, event.clientY);\n if (!target) return;\n setOverGroup(target.group);\n setOverIndex(target.index);\n }\n\n function onPointerUp(): void {\n const from = activeRef.current;\n const to = overRef.current;\n if (from !== null && to !== null) {\n commit(from, to, activeGroupRef.current, overGroupRef.current);\n } else {\n reset();\n }\n }\n\n function onKeyDown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") reset();\n }\n\n window.addEventListener(\"pointermove\", onPointerMove);\n window.addEventListener(\"pointerup\", onPointerUp);\n window.addEventListener(\"pointercancel\", reset);\n window.addEventListener(\"keydown\", onKeyDown);\n return () => {\n window.removeEventListener(\"pointermove\", onPointerMove);\n window.removeEventListener(\"pointerup\", onPointerUp);\n window.removeEventListener(\"pointercancel\", reset);\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [activeIndex, commit, reset, setOverGroup, setOverIndex]);\n\n const handleKeyDown = useCallback(\n (\n index: number,\n group: string | undefined,\n event: ReactKeyboardEvent<HTMLElement>,\n ): void => {\n if (disabled) return;\n const picked = activeIndex !== null;\n\n switch (event.key) {\n case \" \":\n case \"Enter\":\n event.preventDefault();\n if (!picked) {\n setActiveGroup(group);\n setOverGroup(group);\n setActiveIndex(index);\n setOverIndex(index);\n } else if (overIndex !== null) {\n commit(activeIndex, overIndex, activeGroup, overGroup);\n }\n break;\n case \"ArrowDown\":\n case \"ArrowRight\": {\n if (!picked) return;\n event.preventDefault();\n if (overRef.current !== null) {\n setOverIndex(Math.min(overRef.current + 1, itemCount - 1));\n }\n break;\n }\n case \"ArrowUp\":\n case \"ArrowLeft\": {\n if (!picked) return;\n event.preventDefault();\n if (overRef.current !== null) {\n setOverIndex(Math.max(overRef.current - 1, 0));\n }\n break;\n }\n case \"Escape\":\n if (!picked) return;\n event.preventDefault();\n reset();\n break;\n default:\n break;\n }\n },\n [\n activeGroup,\n activeIndex,\n commit,\n overGroup,\n disabled,\n itemCount,\n overIndex,\n reset,\n setActiveGroup,\n setActiveIndex,\n setOverGroup,\n setOverIndex,\n ],\n );\n\n const getItemProps = useCallback(\n (index: number, group?: string): SortableItemProps => ({\n \"data-sortable-index\": index,\n \"data-sortable-group\": group,\n \"data-sortable-active\": (activeIndex === index && activeGroup === group) || undefined,\n onPointerDown: (event) => handlePointerDown(index, group, event),\n onKeyDown: (event) => handleKeyDown(index, group, event),\n tabIndex: disabled ? -1 : 0,\n role: \"option\",\n \"aria-roledescription\": roleDescription,\n \"aria-selected\": activeIndex === index && activeGroup === group,\n }),\n [activeGroup, activeIndex, disabled, handleKeyDown, handlePointerDown, roleDescription],\n );\n\n const getEmptyGroupProps = useCallback(\n (group: string) => ({ \"data-sortable-group\": group, \"data-sortable-empty\": true as const }),\n [],\n );\n\n const getListProps = useCallback(\n () => ({ role: \"listbox\" as const, \"aria-orientation\": \"vertical\" as const }),\n [],\n );\n\n return {\n activeIndex,\n overIndex,\n activeGroup,\n overGroup,\n getItemProps,\n getEmptyGroupProps,\n getListProps,\n cancel: reset,\n setContainer,\n };\n}\n"],"mappings":";;AAmGA,SAAgB,EAAY,GAAY,GAAc,GAAiB;CACnE,IAAI,MAAS,KAAM,IAAO,KAAK,IAAK,KAAK,KAAQ,EAAM,UAAU,KAAM,EAAM,QACzE,OAAO;CAEX,IAAM,IAAO,EAAM,MAAM,GACnB,CAAC,KAAS,EAAK,OAAO,GAAM,CAAC;CAEnC,OADA,EAAK,OAAO,GAAI,GAAG,CAAK,GACjB;AACX;AAcA,SAAS,EAAc,GAA+B,GAAW,GAA6B;CAC1F,IAAI,CAAC,GAAW,OAAO;CACvB,IAAM,KAAU,MAAkC;EAC9C,IAAM,IAAO,EAAQ,sBAAsB;EAC3C,OAAO,KAAK,EAAK,OAAO,KAAK,EAAK,UAAU,KAAK,EAAK,QAAQ,KAAK,EAAK;CAC5E;CAEA,KAAK,IAAM,KAAQ,MAAM,KACrB,EAAU,iBAA8B,uBAAuB,CACnE,GAAG;EACC,IAAI,CAAC,EAAO,CAAI,GAAG;EACnB,IAAM,IAAQ,OAAO,EAAK,QAAQ,aAAa;EAE/C,OADI,OAAO,MAAM,CAAK,IAAU,OACzB;GAAE;GAAO,OAAO,EAAK,QAAQ;EAAc;CACtD;CAEA,KAAK,IAAM,KAAS,MAAM,KACtB,EAAU,iBAA8B,uBAAuB,CACnE,GACI,IAAI,EAAO,CAAK,GAAG,OAAO;EAAE,OAAO;EAAG,OAAO,EAAM,QAAQ;CAAc;CAG7E,OAAO;AACX;AA6CA,SAAgB,EAAY,GAAgD;CACxE,IAAM,EAAE,cAAW,cAAW,cAAW,IAAO,qBAAkB,oBAAoB,GAEhF,CAAC,GAAa,KAAuB,EAAwB,IAAI,GACjE,CAAC,GAAW,KAAqB,EAAwB,IAAI,GAC7D,IAAe,EAA2B,IAAI,GAC9C,IAAe,EAAO,CAAS,GAU/B,IAAY,EAAsB,IAAI,GACtC,IAAU,EAAsB,IAAI,GACpC,CAAC,GAAa,KAAuB,EAA6B,KAAA,CAAS,GAC3E,CAAC,GAAW,KAAqB,EAA6B,KAAA,CAAS,GACvE,IAAiB,EAA2B,KAAA,CAAS,GACrD,IAAe,EAA2B,KAAA,CAAS,GAEnD,IAAiB,GAAa,MAAoC;EAEpE,AADA,EAAe,UAAU,GACzB,EAAoB,CAAK;CAC7B,GAAG,CAAC,CAAC,GAEC,IAAe,GAAa,MAAoC;EAElE,AADA,EAAa,UAAU,GACvB,EAAkB,CAAK;CAC3B,GAAG,CAAC,CAAC,GAEC,IAAiB,GAAa,MAA+B;EAE/D,AADA,EAAU,UAAU,GACpB,EAAoB,CAAK;CAC7B,GAAG,CAAC,CAAC,GAEC,IAAe,GAAa,MAA+B;EAE7D,AADA,EAAQ,UAAU,GAClB,EAAkB,CAAK;CAC3B,GAAG,CAAC,CAAC;CAEL,QAAgB;EACZ,EAAa,UAAU;CAC3B,GAAG,CAAC,CAAS,CAAC;CAEd,IAAM,IAAQ,QAAwB;EAIlC,AAHA,EAAe,KAAA,CAAS,GACxB,EAAa,KAAA,CAAS,GACtB,EAAe,IAAI,GACnB,EAAa,IAAI;CACrB,GAAG;EAAC;EAAgB;EAAgB;EAAc;CAAY,CAAC;CAE/D,QAAgB;EACZ,EAAM;CACV,GAAG,CAAC,GAAW,CAAK,CAAC;CAcrB,IAAM,IAAS,GACV,GAAc,GAAY,GAAoB,MAA2B;EAItE,CAHI,MAAS,KAAM,MAAc,MAC7B,EAAa,QAAQ;GAAE;GAAM;GAAI;GAAW;EAAQ,CAAC,GAEzD,EAAM;CACV,GACA,CAAC,CAAK,CACV,GAEM,IAAe,GAAa,MAAmC;EACjE,EAAa,UAAU;CAC3B,GAAG,CAAC,CAAC,GAEC,IAAoB,GACrB,GAAe,GAA2B,MAAgD;EACnF,MACJ,EAAM,cAAc,oBAAoB,EAAM,SAAS,GACvD,EAAe,CAAK,GACpB,EAAa,CAAK,GAClB,EAAe,CAAK,GACpB,EAAa,CAAK;CACtB,GACA;EAAC;EAAU;EAAgB;EAAgB;EAAc;CAAY,CACzE;CAEA,QAAgB;EACZ,IAAI,MAAgB,MAAM;EAE1B,SAAS,EAAc,GAA2B;GAC9C,IAAM,IAAS,EAAc,EAAa,SAAS,EAAM,SAAS,EAAM,OAAO;GAC1E,MACL,EAAa,EAAO,KAAK,GACzB,EAAa,EAAO,KAAK;EAC7B;EAEA,SAAS,IAAoB;GACzB,IAAM,IAAO,EAAU,SACjB,IAAK,EAAQ;GACnB,AAAI,MAAS,QAAQ,MAAO,OACxB,EAAO,GAAM,GAAI,EAAe,SAAS,EAAa,OAAO,IAE7D,EAAM;EAEd;EAEA,SAAS,EAAU,GAA4B;GAC3C,AAAI,EAAM,QAAQ,YAAU,EAAM;EACtC;EAMA,OAJA,OAAO,iBAAiB,eAAe,CAAa,GACpD,OAAO,iBAAiB,aAAa,CAAW,GAChD,OAAO,iBAAiB,iBAAiB,CAAK,GAC9C,OAAO,iBAAiB,WAAW,CAAS,SAC/B;GAIT,AAHA,OAAO,oBAAoB,eAAe,CAAa,GACvD,OAAO,oBAAoB,aAAa,CAAW,GACnD,OAAO,oBAAoB,iBAAiB,CAAK,GACjD,OAAO,oBAAoB,WAAW,CAAS;EACnD;CACJ,GAAG;EAAC;EAAa;EAAQ;EAAO;EAAc;CAAY,CAAC;CAE3D,IAAM,IAAgB,GAEd,GACA,GACA,MACO;EACP,IAAI,GAAU;EACd,IAAM,IAAS,MAAgB;EAE/B,QAAQ,EAAM,KAAd;GACI,KAAK;GACL,KAAK;IAED,AADA,EAAM,eAAe,GAChB,IAKM,MAAc,QACrB,EAAO,GAAa,GAAW,GAAa,CAAS,KALrD,EAAe,CAAK,GACpB,EAAa,CAAK,GAClB,EAAe,CAAK,GACpB,EAAa,CAAK;IAItB;GACJ,KAAK;GACL,KAAK;IACD,IAAI,CAAC,GAAQ;IAEb,AADA,EAAM,eAAe,GACjB,EAAQ,YAAY,QACpB,EAAa,KAAK,IAAI,EAAQ,UAAU,GAAG,IAAY,CAAC,CAAC;IAE7D;GAEJ,KAAK;GACL,KAAK;IACD,IAAI,CAAC,GAAQ;IAEb,AADA,EAAM,eAAe,GACjB,EAAQ,YAAY,QACpB,EAAa,KAAK,IAAI,EAAQ,UAAU,GAAG,CAAC,CAAC;IAEjD;GAEJ,KAAK;IACD,IAAI,CAAC,GAAQ;IAEb,AADA,EAAM,eAAe,GACrB,EAAM;IACN;GACJ,SACI;EACR;CACJ,GACA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACJ,CACJ;CA2BA,OAAO;EACH;EACA;EACA;EACA;EACA,cA9BiB,GAChB,GAAe,OAAuC;GACnD,uBAAuB;GACvB,uBAAuB;GACvB,wBAAyB,MAAgB,KAAS,MAAgB,KAAU,KAAA;GAC5E,gBAAgB,MAAU,EAAkB,GAAO,GAAO,CAAK;GAC/D,YAAY,MAAU,EAAc,GAAO,GAAO,CAAK;GACvD,UAAU,IAAW,KAAK;GAC1B,MAAM;GACN,wBAAwB;GACxB,iBAAiB,MAAgB,KAAS,MAAgB;EAC9D,IACA;GAAC;GAAa;GAAa;GAAU;GAAe;GAAmB;EAAe,CAkBtF;EACA,oBAhBuB,GACtB,OAAmB;GAAE,uBAAuB;GAAO,uBAAuB;EAAc,IACzF,CAAC,CAcD;EACA,cAZiB,SACV;GAAE,MAAM;GAAoB,oBAAoB;EAAoB,IAC3E,CAAC,CAUD;EACA,QAAQ;EACR;CACJ;AACJ"}