tempest-react-sdk 0.39.0 → 0.40.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 (475) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +1 -1
  2. package/dist/access/access-control-context.cjs.map +1 -1
  3. package/dist/access/use-can.cjs.map +1 -1
  4. package/dist/app/AppProviders.cjs.map +1 -1
  5. package/dist/app/AppProviders.js.map +1 -1
  6. package/dist/audio/use-audio-recorder.cjs.map +1 -1
  7. package/dist/audio/use-audio.cjs.map +1 -1
  8. package/dist/audio/use-microphone.cjs.map +1 -1
  9. package/dist/auth/create-auth-store.cjs.map +1 -1
  10. package/dist/auth/lazy-with-retry.cjs.map +1 -1
  11. package/dist/auth/passkey.cjs.map +1 -1
  12. package/dist/auth/passkey.js.map +1 -1
  13. package/dist/auth/use-passkey.cjs.map +1 -1
  14. package/dist/br/BrazilMap.cjs +1 -1
  15. package/dist/br/BrazilMap.cjs.map +1 -1
  16. package/dist/br/BrazilMap.js +2 -2
  17. package/dist/br/BrazilMap.js.map +1 -1
  18. package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
  19. package/dist/br/BrazilStateCitySelect.js.map +1 -1
  20. package/dist/br/BrazilStateMap.cjs +1 -1
  21. package/dist/br/BrazilStateMap.cjs.map +1 -1
  22. package/dist/br/BrazilStateMap.js +2 -2
  23. package/dist/br/BrazilStateMap.js.map +1 -1
  24. package/dist/br/MapLegend.cjs.map +1 -1
  25. package/dist/br/MapLegend.js.map +1 -1
  26. package/dist/br/MapMarkers.cjs.map +1 -1
  27. package/dist/br/MapMarkers.js.map +1 -1
  28. package/dist/br/MunicipalitySearch.cjs.map +1 -1
  29. package/dist/br/MunicipalitySearch.js.map +1 -1
  30. package/dist/br/PixQRCode.cjs.map +1 -1
  31. package/dist/br/PixQRCode.js.map +1 -1
  32. package/dist/br/use-map-hover.cjs.map +1 -1
  33. package/dist/br/use-map-zoom.cjs.map +1 -1
  34. package/dist/capture/media-recorder.cjs +1 -1
  35. package/dist/capture/media-recorder.js +2 -2
  36. package/dist/capture/use-barcode-scanner.cjs +1 -1
  37. package/dist/capture/use-barcode-scanner.cjs.map +1 -1
  38. package/dist/capture/use-barcode-scanner.js +2 -2
  39. package/dist/capture/use-barcode-scanner.js.map +1 -1
  40. package/dist/capture/use-screen-capture.cjs.map +1 -1
  41. package/dist/capture/use-speech-recognition.cjs.map +1 -1
  42. package/dist/capture/use-torch.cjs.map +1 -1
  43. package/dist/capture/use-video-recorder.cjs.map +1 -1
  44. package/dist/charts/AreaChart.cjs.map +1 -1
  45. package/dist/charts/AreaChart.js.map +1 -1
  46. package/dist/charts/BarChart.cjs.map +1 -1
  47. package/dist/charts/BarChart.js.map +1 -1
  48. package/dist/charts/LineChart.cjs.map +1 -1
  49. package/dist/charts/LineChart.js.map +1 -1
  50. package/dist/charts/PieChart.cjs.map +1 -1
  51. package/dist/charts/PieChart.js.map +1 -1
  52. package/dist/charts/RadarChart.cjs.map +1 -1
  53. package/dist/charts/RadarChart.js.map +1 -1
  54. package/dist/charts/use-chart-colors.cjs.map +1 -1
  55. package/dist/components/AIChat/AIChat.cjs.map +1 -1
  56. package/dist/components/AIChat/AIChat.js.map +1 -1
  57. package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
  58. package/dist/components/AIChat/AIChatComposer.js.map +1 -1
  59. package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
  60. package/dist/components/AIChat/AIChatTurn.js.map +1 -1
  61. package/dist/components/Accordion/Accordion.cjs.map +1 -1
  62. package/dist/components/Accordion/Accordion.js.map +1 -1
  63. package/dist/components/Alert/Alert.cjs.map +1 -1
  64. package/dist/components/Alert/Alert.js.map +1 -1
  65. package/dist/components/AppBar/AppBar.cjs.map +1 -1
  66. package/dist/components/AppBar/AppBar.js.map +1 -1
  67. package/dist/components/AppShell/AppShell.cjs.map +1 -1
  68. package/dist/components/AppShell/AppShell.js.map +1 -1
  69. package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
  70. package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
  71. package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
  72. package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
  73. package/dist/components/Avatar/Avatar.cjs.map +1 -1
  74. package/dist/components/Avatar/Avatar.js.map +1 -1
  75. package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -1
  76. package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -1
  77. package/dist/components/Badge/Badge.cjs.map +1 -1
  78. package/dist/components/Badge/Badge.js.map +1 -1
  79. package/dist/components/Banner/Banner.cjs.map +1 -1
  80. package/dist/components/Banner/Banner.js.map +1 -1
  81. package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
  82. package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
  83. package/dist/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
  84. package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
  85. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  86. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  87. package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
  88. package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  89. package/dist/components/Button/Button.cjs.map +1 -1
  90. package/dist/components/Button/Button.js.map +1 -1
  91. package/dist/components/Calendar/Calendar.cjs +1 -1
  92. package/dist/components/Calendar/Calendar.cjs.map +1 -1
  93. package/dist/components/Calendar/Calendar.js +38 -41
  94. package/dist/components/Calendar/Calendar.js.map +1 -1
  95. package/dist/components/Card/Card.cjs.map +1 -1
  96. package/dist/components/Card/Card.js.map +1 -1
  97. package/dist/components/Carousel/Carousel.cjs.map +1 -1
  98. package/dist/components/Carousel/Carousel.js.map +1 -1
  99. package/dist/components/Chat/Chat.cjs.map +1 -1
  100. package/dist/components/Chat/Chat.js.map +1 -1
  101. package/dist/components/Chat/ChatComposer.cjs.map +1 -1
  102. package/dist/components/Chat/ChatComposer.js.map +1 -1
  103. package/dist/components/Chat/chat-groups.cjs +1 -1
  104. package/dist/components/Chat/chat-groups.cjs.map +1 -1
  105. package/dist/components/Chat/chat-groups.js +2 -2
  106. package/dist/components/Chat/chat-groups.js.map +1 -1
  107. package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
  108. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  109. package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
  110. package/dist/components/ChipInput/ChipInput.js.map +1 -1
  111. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  112. package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
  113. package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
  114. package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
  115. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  116. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  117. package/dist/components/Combobox/Combobox.js.map +1 -1
  118. package/dist/components/Command/Command.cjs.map +1 -1
  119. package/dist/components/Command/Command.js.map +1 -1
  120. package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
  121. package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
  122. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  123. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  124. package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
  125. package/dist/components/CopyButton/CopyButton.js.map +1 -1
  126. package/dist/components/DataList/DataList.cjs.map +1 -1
  127. package/dist/components/DataList/DataList.js.map +1 -1
  128. package/dist/components/DataTable/DataTable.cjs +1 -1
  129. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  130. package/dist/components/DataTable/DataTable.js +2 -2
  131. package/dist/components/DataTable/DataTable.js.map +1 -1
  132. package/dist/components/DataTable/EditableCell.cjs.map +1 -1
  133. package/dist/components/DataTable/EditableCell.js.map +1 -1
  134. package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
  135. package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
  136. package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
  137. package/dist/components/DescriptionList/DescriptionList.cjs.map +1 -1
  138. package/dist/components/DescriptionList/DescriptionList.js.map +1 -1
  139. package/dist/components/Divider/Divider.cjs.map +1 -1
  140. package/dist/components/Divider/Divider.js.map +1 -1
  141. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  142. package/dist/components/Drawer/Drawer.js.map +1 -1
  143. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  144. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  145. package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
  146. package/dist/components/Dropzone/Dropzone.js.map +1 -1
  147. package/dist/components/EmptyState/EmptyState.cjs.map +1 -1
  148. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  149. package/dist/components/ErrorState/ErrorState.cjs.map +1 -1
  150. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  151. package/dist/components/FileUpload/FileUpload.cjs +1 -1
  152. package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
  153. package/dist/components/FileUpload/FileUpload.js +1 -1
  154. package/dist/components/FileUpload/FileUpload.js.map +1 -1
  155. package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
  156. package/dist/components/FilterBar/FilterBar.js.map +1 -1
  157. package/dist/components/FloatingActionButton/FloatingActionButton.cjs.map +1 -1
  158. package/dist/components/FloatingActionButton/FloatingActionButton.js.map +1 -1
  159. package/dist/components/Form/Form.cjs.map +1 -1
  160. package/dist/components/Form/Form.js.map +1 -1
  161. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  162. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  163. package/dist/components/Image/Image.cjs.map +1 -1
  164. package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
  165. package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
  166. package/dist/components/ImageCropper/ImageCropper.js +1 -1
  167. package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
  168. package/dist/components/Input/Input.cjs.map +1 -1
  169. package/dist/components/Input/Input.js.map +1 -1
  170. package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
  171. package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
  172. package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
  173. package/dist/components/InstallButton/InstallButton.js.map +1 -1
  174. package/dist/components/Kanban/Kanban.cjs.map +1 -1
  175. package/dist/components/Kanban/Kanban.js.map +1 -1
  176. package/dist/components/Label/Label.cjs.map +1 -1
  177. package/dist/components/Label/Label.js.map +1 -1
  178. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  179. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  180. package/dist/components/ListTile/ListTile.cjs.map +1 -1
  181. package/dist/components/ListTile/ListTile.js.map +1 -1
  182. package/dist/components/Markdown/Markdown.cjs +1 -1
  183. package/dist/components/Markdown/Markdown.cjs.map +1 -1
  184. package/dist/components/Markdown/Markdown.js +2 -2
  185. package/dist/components/Markdown/Markdown.js.map +1 -1
  186. package/dist/components/Masonry/Masonry.cjs.map +1 -1
  187. package/dist/components/Masonry/Masonry.js.map +1 -1
  188. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  189. package/dist/components/Menubar/Menubar.js.map +1 -1
  190. package/dist/components/Modal/Modal.cjs.map +1 -1
  191. package/dist/components/Modal/Modal.js.map +1 -1
  192. package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
  193. package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
  194. package/dist/components/Money/Money.cjs.map +1 -1
  195. package/dist/components/Money/Money.js.map +1 -1
  196. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  197. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  198. package/dist/components/NProgress/NProgress.cjs.map +1 -1
  199. package/dist/components/Navbar/Navbar.cjs.map +1 -1
  200. package/dist/components/Navbar/Navbar.js.map +1 -1
  201. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  202. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  203. package/dist/components/NavigationRail/NavigationRail.cjs.map +1 -1
  204. package/dist/components/NavigationRail/NavigationRail.js.map +1 -1
  205. package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
  206. package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
  207. package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -1
  208. package/dist/components/OfflineIndicator/OfflineIndicator.cjs.map +1 -1
  209. package/dist/components/OfflineIndicator/OfflineIndicator.js.map +1 -1
  210. package/dist/components/Page/Page.cjs.map +1 -1
  211. package/dist/components/Page/Page.js.map +1 -1
  212. package/dist/components/Pagination/Pagination.cjs.map +1 -1
  213. package/dist/components/Pagination/Pagination.js.map +1 -1
  214. package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
  215. package/dist/components/PasswordInput/PasswordInput.js.map +1 -1
  216. package/dist/components/PinInput/PinInput.cjs.map +1 -1
  217. package/dist/components/PinInput/PinInput.js.map +1 -1
  218. package/dist/components/Popover/Popover.cjs.map +1 -1
  219. package/dist/components/Popover/Popover.js.map +1 -1
  220. package/dist/components/Portal/Portal.cjs.map +1 -1
  221. package/dist/components/Progress/Progress.cjs.map +1 -1
  222. package/dist/components/Progress/Progress.js.map +1 -1
  223. package/dist/components/QRCode/QRCode.cjs.map +1 -1
  224. package/dist/components/QRCode/QRCode.js.map +1 -1
  225. package/dist/components/Radio/Radio.cjs.map +1 -1
  226. package/dist/components/Radio/Radio.js.map +1 -1
  227. package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
  228. package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
  229. package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
  230. package/dist/components/RatingStars/RatingStars.js.map +1 -1
  231. package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
  232. package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
  233. package/dist/components/RelativeTime/RelativeTime.cjs.map +1 -1
  234. package/dist/components/RelativeTime/RelativeTime.js.map +1 -1
  235. package/dist/components/Resizable/Resizable.cjs.map +1 -1
  236. package/dist/components/Resizable/Resizable.js.map +1 -1
  237. package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
  238. package/dist/components/Scheduler/Scheduler.js.map +1 -1
  239. package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
  240. package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
  241. package/dist/components/SearchBar/SearchBar.js.map +1 -1
  242. package/dist/components/SegmentedControl/SegmentedControl.cjs.map +1 -1
  243. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  244. package/dist/components/Select/Select.cjs.map +1 -1
  245. package/dist/components/Select/Select.js.map +1 -1
  246. package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
  247. package/dist/components/Sidebar/Sidebar.js.map +1 -1
  248. package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -1
  249. package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
  250. package/dist/components/Slider/Slider.cjs.map +1 -1
  251. package/dist/components/Slider/Slider.js.map +1 -1
  252. package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
  253. package/dist/components/Sparkline/Sparkline.js.map +1 -1
  254. package/dist/components/Spinner/Spinner.cjs.map +1 -1
  255. package/dist/components/Spinner/Spinner.js.map +1 -1
  256. package/dist/components/Stat/Stat.cjs.map +1 -1
  257. package/dist/components/Stat/Stat.js.map +1 -1
  258. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  259. package/dist/components/Stepper/Stepper.js.map +1 -1
  260. package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
  261. package/dist/components/StepperInput/StepperInput.js.map +1 -1
  262. package/dist/components/Switch/Switch.cjs.map +1 -1
  263. package/dist/components/Switch/Switch.js.map +1 -1
  264. package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
  265. package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
  266. package/dist/components/Table/Table.cjs.map +1 -1
  267. package/dist/components/Table/Table.js.map +1 -1
  268. package/dist/components/Tabs/Tabs.cjs.map +1 -1
  269. package/dist/components/Tabs/Tabs.js.map +1 -1
  270. package/dist/components/Tag/Tag.cjs.map +1 -1
  271. package/dist/components/Tag/Tag.js.map +1 -1
  272. package/dist/components/Textarea/Textarea.cjs.map +1 -1
  273. package/dist/components/Textarea/Textarea.js.map +1 -1
  274. package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
  275. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  276. package/dist/components/Timeline/Timeline.cjs.map +1 -1
  277. package/dist/components/Timeline/Timeline.js.map +1 -1
  278. package/dist/components/Toast/ToastProvider.cjs.map +1 -1
  279. package/dist/components/Toast/ToastProvider.js.map +1 -1
  280. package/dist/components/Toggle/Toggle.cjs.map +1 -1
  281. package/dist/components/ToggleGroup/ToggleGroup.cjs.map +1 -1
  282. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  283. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  284. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  285. package/dist/components/Tour/Tour.cjs.map +1 -1
  286. package/dist/components/Tour/Tour.js.map +1 -1
  287. package/dist/components/Transfer/Transfer.cjs.map +1 -1
  288. package/dist/components/Transfer/Transfer.js.map +1 -1
  289. package/dist/components/TreeView/TreeView.cjs +1 -1
  290. package/dist/components/TreeView/TreeView.cjs.map +1 -1
  291. package/dist/components/TreeView/TreeView.js +1 -4
  292. package/dist/components/TreeView/TreeView.js.map +1 -1
  293. package/dist/components/UpdatePrompt/UpdatePrompt.cjs.map +1 -1
  294. package/dist/components/UpdatePrompt/UpdatePrompt.js.map +1 -1
  295. package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
  296. package/dist/components/VirtualList/VirtualList.js.map +1 -1
  297. package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
  298. package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
  299. package/dist/components/VisuallyHidden/VisuallyHidden.cjs.map +1 -1
  300. package/dist/components/Wizard/Wizard.cjs.map +1 -1
  301. package/dist/components/Wizard/Wizard.js.map +1 -1
  302. package/dist/data/data-provider-context.cjs.map +1 -1
  303. package/dist/data/use-resource.cjs.map +1 -1
  304. package/dist/editor/RichTextEditor.cjs.map +1 -1
  305. package/dist/editor/RichTextEditor.js.map +1 -1
  306. package/dist/error-boundary/use-error-handler.cjs.map +1 -1
  307. package/dist/feature-flags/FeatureFlagsProvider.cjs.map +1 -1
  308. package/dist/forms/FormField.cjs.map +1 -1
  309. package/dist/forms/masked-inputs.cjs +1 -1
  310. package/dist/forms/masked-inputs.cjs.map +1 -1
  311. package/dist/forms/masked-inputs.js +1 -1
  312. package/dist/forms/masked-inputs.js.map +1 -1
  313. package/dist/forms/use-viacep.cjs.map +1 -1
  314. package/dist/forms/use-zod-form.cjs.map +1 -1
  315. package/dist/forms/zod-resolver.cjs.map +1 -1
  316. package/dist/forms/zod-resolver.js.map +1 -1
  317. package/dist/geo/TrajectoryMap.cjs.map +1 -1
  318. package/dist/geo/TrajectoryMap.js.map +1 -1
  319. package/dist/geo/leaflet-map.cjs.map +1 -1
  320. package/dist/geo/leaflet-map.js.map +1 -1
  321. package/dist/geo/use-position-tracker.cjs.map +1 -1
  322. package/dist/hooks/use-announce.cjs.map +1 -1
  323. package/dist/hooks/use-async.cjs.map +1 -1
  324. package/dist/hooks/use-before-install-prompt.cjs.map +1 -1
  325. package/dist/hooks/use-breakpoint.cjs.map +1 -1
  326. package/dist/hooks/use-click-outside.cjs.map +1 -1
  327. package/dist/hooks/use-client-filter.cjs.map +1 -1
  328. package/dist/hooks/use-clipboard.cjs.map +1 -1
  329. package/dist/hooks/use-counter.cjs.map +1 -1
  330. package/dist/hooks/use-debounce.cjs.map +1 -1
  331. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  332. package/dist/hooks/use-disclosure.cjs.map +1 -1
  333. package/dist/hooks/use-document-visibility.cjs.map +1 -1
  334. package/dist/hooks/use-event-listener.cjs.map +1 -1
  335. package/dist/hooks/use-geolocation.cjs.map +1 -1
  336. package/dist/hooks/use-hover.cjs.map +1 -1
  337. package/dist/hooks/use-idle.cjs.map +1 -1
  338. package/dist/hooks/use-install-prompt.cjs +1 -1
  339. package/dist/hooks/use-install-prompt.cjs.map +1 -1
  340. package/dist/hooks/use-install-prompt.js +1 -1
  341. package/dist/hooks/use-install-prompt.js.map +1 -1
  342. package/dist/hooks/use-intersection-observer.cjs.map +1 -1
  343. package/dist/hooks/use-interval.cjs.map +1 -1
  344. package/dist/hooks/use-is-first-render.cjs.map +1 -1
  345. package/dist/hooks/use-keyboard-shortcut.cjs +1 -1
  346. package/dist/hooks/use-keyboard-shortcut.cjs.map +1 -1
  347. package/dist/hooks/use-keyboard-shortcut.js +1 -1
  348. package/dist/hooks/use-keyboard-shortcut.js.map +1 -1
  349. package/dist/hooks/use-list-state.cjs.map +1 -1
  350. package/dist/hooks/use-local-storage.cjs.map +1 -1
  351. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  352. package/dist/hooks/use-long-press.cjs.map +1 -1
  353. package/dist/hooks/use-map.cjs.map +1 -1
  354. package/dist/hooks/use-media-devices.cjs.map +1 -1
  355. package/dist/hooks/use-media-permission.cjs.map +1 -1
  356. package/dist/hooks/use-media-query.cjs.map +1 -1
  357. package/dist/hooks/use-object-url.cjs.map +1 -1
  358. package/dist/hooks/use-online.cjs.map +1 -1
  359. package/dist/hooks/use-pagination.cjs.map +1 -1
  360. package/dist/hooks/use-previous.cjs.map +1 -1
  361. package/dist/hooks/use-queue.cjs.map +1 -1
  362. package/dist/hooks/use-resize-observer.cjs.map +1 -1
  363. package/dist/hooks/use-scroll-overflow.cjs.map +1 -1
  364. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  365. package/dist/hooks/use-set.cjs.map +1 -1
  366. package/dist/hooks/use-sortable.cjs +1 -1
  367. package/dist/hooks/use-sortable.cjs.map +1 -1
  368. package/dist/hooks/use-sortable.js +0 -2
  369. package/dist/hooks/use-sortable.js.map +1 -1
  370. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  371. package/dist/hooks/use-storage-estimate.cjs.map +1 -1
  372. package/dist/hooks/use-throttle.cjs.map +1 -1
  373. package/dist/hooks/use-timeout.cjs.map +1 -1
  374. package/dist/hooks/use-toggle.cjs.map +1 -1
  375. package/dist/hooks/use-window-size.cjs.map +1 -1
  376. package/dist/http/api-client.cjs +1 -1
  377. package/dist/http/api-client.cjs.map +1 -1
  378. package/dist/http/api-client.js +7 -5
  379. package/dist/http/api-client.js.map +1 -1
  380. package/dist/http/resumable-upload.cjs +1 -1
  381. package/dist/http/resumable-upload.cjs.map +1 -1
  382. package/dist/http/resumable-upload.js +1 -1
  383. package/dist/http/resumable-upload.js.map +1 -1
  384. package/dist/http/use-poll.cjs.map +1 -1
  385. package/dist/i18n/I18nProvider.cjs.map +1 -1
  386. package/dist/icons/Icon.cjs.map +1 -1
  387. package/dist/icons/IconProvider.cjs.map +1 -1
  388. package/dist/icons/icon-context.cjs.map +1 -1
  389. package/dist/icons/use-icon.cjs.map +1 -1
  390. package/dist/imaging/use-image-processing.cjs.map +1 -1
  391. package/dist/oauth/GoogleSignIn.cjs.map +1 -1
  392. package/dist/oauth/GoogleSignIn.js.map +1 -1
  393. package/dist/oauth/use-oauth-callback.cjs.map +1 -1
  394. package/dist/offline/use-offline-sync.cjs.map +1 -1
  395. package/dist/push/use-push-subscription.cjs.map +1 -1
  396. package/dist/query/QueryProvider.cjs.map +1 -1
  397. package/dist/query/constants.cjs +1 -1
  398. package/dist/query/constants.cjs.map +1 -1
  399. package/dist/query/constants.js +10 -10
  400. package/dist/query/constants.js.map +1 -1
  401. package/dist/query/create-query-keys.cjs +1 -1
  402. package/dist/query/create-query-keys.cjs.map +1 -1
  403. package/dist/query/create-query-keys.js +1 -1
  404. package/dist/query/create-query-keys.js.map +1 -1
  405. package/dist/query/offline-persistence.cjs.map +1 -1
  406. package/dist/query/use-cursor-query.cjs.map +1 -1
  407. package/dist/query/use-offline-mutation.cjs.map +1 -1
  408. package/dist/query/use-paginated-query.cjs.map +1 -1
  409. package/dist/router/AppRouter.cjs +1 -1
  410. package/dist/router/AppRouter.cjs.map +1 -1
  411. package/dist/router/AppRouter.js +7 -2
  412. package/dist/router/AppRouter.js.map +1 -1
  413. package/dist/sse/use-event-stream.cjs.map +1 -1
  414. package/dist/store/create-store.cjs.map +1 -1
  415. package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
  416. package/dist/telemetry/TelemetryProvider.cjs.map +1 -1
  417. package/dist/tempest-react-sdk.d.ts +25 -26
  418. package/dist/theme/ThemeProvider.cjs.map +1 -1
  419. package/dist/theme/color.cjs +1 -1
  420. package/dist/theme/color.cjs.map +1 -1
  421. package/dist/theme/color.js +1 -1
  422. package/dist/theme/color.js.map +1 -1
  423. package/dist/utils/cn.cjs +1 -1
  424. package/dist/utils/cn.cjs.map +1 -1
  425. package/dist/utils/cn.js +1 -1
  426. package/dist/utils/cn.js.map +1 -1
  427. package/dist/utils/objects.cjs +1 -1
  428. package/dist/utils/objects.cjs.map +1 -1
  429. package/dist/utils/objects.js +1 -1
  430. package/dist/utils/objects.js.map +1 -1
  431. package/dist/utils/xlsx.cjs +1 -1
  432. package/dist/utils/xlsx.cjs.map +1 -1
  433. package/dist/utils/xlsx.js +3 -3
  434. package/dist/utils/xlsx.js.map +1 -1
  435. package/dist/vision/core/exceptions.cjs.map +1 -1
  436. package/dist/vision/core/exceptions.js.map +1 -1
  437. package/dist/vision/core/metadata.cjs +1 -1
  438. package/dist/vision/core/metadata.cjs.map +1 -1
  439. package/dist/vision/core/metadata.js +1 -1
  440. package/dist/vision/core/metadata.js.map +1 -1
  441. package/dist/vision/io/image.cjs +1 -1
  442. package/dist/vision/io/image.cjs.map +1 -1
  443. package/dist/vision/io/image.js +4 -2
  444. package/dist/vision/io/image.js.map +1 -1
  445. package/dist/vision/preprocess/image.cjs +1 -1
  446. package/dist/vision/preprocess/image.cjs.map +1 -1
  447. package/dist/vision/preprocess/image.js +4 -2
  448. package/dist/vision/preprocess/image.js.map +1 -1
  449. package/dist/vision/tasks/base.cjs +1 -1
  450. package/dist/vision/tasks/base.cjs.map +1 -1
  451. package/dist/vision/tasks/base.js +3 -1
  452. package/dist/vision/tasks/base.js.map +1 -1
  453. package/dist/vision/tasks/classifier.cjs +1 -1
  454. package/dist/vision/tasks/classifier.cjs.map +1 -1
  455. package/dist/vision/tasks/classifier.js +2 -2
  456. package/dist/vision/tasks/classifier.js.map +1 -1
  457. package/dist/vision/tasks/detectClassify.cjs +1 -1
  458. package/dist/vision/tasks/detectClassify.cjs.map +1 -1
  459. package/dist/vision/tasks/detectClassify.js +16 -15
  460. package/dist/vision/tasks/detectClassify.js.map +1 -1
  461. package/dist/vision/use-camera-stream.cjs.map +1 -1
  462. package/dist/vision/use-live-luminance.cjs.map +1 -1
  463. package/dist/vite/create-vite-config.cjs +1 -1
  464. package/dist/vite/create-vite-config.cjs.map +1 -1
  465. package/dist/vite/create-vite-config.js +3 -3
  466. package/dist/vite/create-vite-config.js.map +1 -1
  467. package/dist/vite/tempest-icons.cjs.map +1 -1
  468. package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
  469. package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
  470. package/dist/ws/use-web-socket.cjs +1 -1
  471. package/dist/ws/use-web-socket.cjs.map +1 -1
  472. package/dist/ws/use-web-socket.js +5 -3
  473. package/dist/ws/use-web-socket.js.map +1 -1
  474. package/package.json +2 -2
  475. package/template/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"use-list-state.cjs","names":[],"sources":["../../src/hooks/use-list-state.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\n\nexport interface ReorderPayload {\n from: number;\n to: number;\n}\n\nexport interface ListStateHandlers<T> {\n append: (...items: T[]) => void;\n prepend: (...items: T[]) => void;\n insert: (index: number, ...items: T[]) => void;\n remove: (...indices: number[]) => void;\n reorder: (payload: ReorderPayload) => void;\n setItem: (index: number, item: T) => void;\n setState: (items: T[]) => void;\n apply: (fn: (item: T, index: number) => T) => void;\n clear: () => void;\n}\n\n/**\n * Manage an array as state with a rich set of immutable handlers.\n *\n * @typeParam T - element type.\n * @param initial - initial list (default `[]`).\n * @returns Tuple `[list, handlers]`.\n */\nexport function useListState<T>(initial: T[] = []): [T[], ListStateHandlers<T>] {\n const [list, setList] = useState<T[]>(initial);\n\n const append = useCallback((...items: T[]): void => {\n setList((current) => [...current, ...items]);\n }, []);\n\n const prepend = useCallback((...items: T[]): void => {\n setList((current) => [...items, ...current]);\n }, []);\n\n const insert = useCallback((index: number, ...items: T[]): void => {\n setList((current) => [...current.slice(0, index), ...items, ...current.slice(index)]);\n }, []);\n\n const remove = useCallback((...indices: number[]): void => {\n const drop = new Set(indices);\n setList((current) => current.filter((_, index) => !drop.has(index)));\n }, []);\n\n const reorder = useCallback(({ from, to }: ReorderPayload): void => {\n setList((current) => {\n const next = [...current];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved);\n return next;\n });\n }, []);\n\n const setItem = useCallback((index: number, item: T): void => {\n setList((current) => current.map((value, i) => (i === index ? item : value)));\n }, []);\n\n const setState = useCallback((items: T[]): void => setList(items), []);\n\n const apply = useCallback((fn: (item: T, index: number) => T): void => {\n setList((current) => current.map(fn));\n }, []);\n\n const clear = useCallback((): void => setList([]), []);\n\n const handlers = useMemo<ListStateHandlers<T>>(\n () => ({\n append,\n prepend,\n insert,\n remove,\n reorder,\n setItem,\n setState,\n apply,\n clear,\n }),\n [append, prepend, insert, remove, reorder, setItem, setState, apply, clear],\n );\n\n return [list, handlers];\n}\n"],"mappings":"uBA0BA,SAAgB,EAAgB,EAAe,CAAC,EAAgC,CAC5E,GAAM,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,CAAyB,CAAO,EAEvC,GAAA,EAAA,EAAA,YAAA,EAAsB,GAAG,IAAqB,CAChD,EAAS,GAAY,CAAC,GAAG,EAAS,GAAG,CAAK,CAAC,CAC/C,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,EAAuB,GAAG,IAAqB,CACjD,EAAS,GAAY,CAAC,GAAG,EAAO,GAAG,CAAO,CAAC,CAC/C,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,EAAsB,EAAe,GAAG,IAAqB,CAC/D,EAAS,GAAY,CAAC,GAAG,EAAQ,MAAM,EAAG,CAAK,EAAG,GAAG,EAAO,GAAG,EAAQ,MAAM,CAAK,CAAC,CAAC,CACxF,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,EAAsB,GAAG,IAA4B,CACvD,IAAM,EAAO,IAAI,IAAI,CAAO,EAC5B,EAAS,GAAY,EAAQ,QAAQ,EAAG,IAAU,CAAC,EAAK,IAAI,CAAK,CAAC,CAAC,CACvE,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,EAAuB,CAAE,OAAM,QAA+B,CAChE,EAAS,GAAY,CACjB,IAAM,EAAO,CAAC,GAAG,CAAO,EAClB,CAAC,GAAS,EAAK,OAAO,EAAM,CAAC,EAEnC,OADA,EAAK,OAAO,EAAI,EAAG,CAAK,EACjB,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,EAAuB,EAAe,IAAkB,CAC1D,EAAS,GAAY,EAAQ,KAAK,EAAO,IAAO,IAAM,EAAQ,EAAO,CAAM,CAAC,CAChF,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,CAAwB,GAAqB,EAAQ,CAAK,EAAG,CAAC,CAAC,EAE/D,GAAA,EAAA,EAAA,YAAA,CAAqB,GAA4C,CACnE,EAAS,GAAY,EAAQ,IAAI,CAAE,CAAC,CACxC,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,KAAgC,EAAQ,CAAC,CAAC,EAAG,CAAC,CAAC,EAiBrD,MAAO,CAAC,GAAA,EAAA,EAAA,QAAA,MAdG,CACH,SACA,UACA,SACA,SACA,UACA,UACA,WACA,QACA,OACJ,GACA,CAAC,EAAQ,EAAS,EAAQ,EAAQ,EAAS,EAAS,EAAU,EAAO,CAAK,CAGhE,CAAQ,CAC1B"}
1
+ {"version":3,"file":"use-list-state.cjs","names":[],"sources":["../../src/hooks/use-list-state.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\n\nexport interface ReorderPayload {\n from: number;\n to: number;\n}\n\nexport interface ListStateHandlers<T> {\n append: (...items: T[]) => void;\n prepend: (...items: T[]) => void;\n insert: (index: number, ...items: T[]) => void;\n remove: (...indices: number[]) => void;\n reorder: (payload: ReorderPayload) => void;\n setItem: (index: number, item: T) => void;\n setState: (items: T[]) => void;\n apply: (fn: (item: T, index: number) => T) => void;\n clear: () => void;\n}\n\n/**\n * Manage an array as state with a rich set of immutable handlers.\n *\n * @typeParam T - element type.\n * @param initial - initial list (default `[]`).\n * @returns Tuple `[list, handlers]`.\n */\nexport function useListState<T>(initial: T[] = []): [T[], ListStateHandlers<T>] {\n const [list, setList] = useState<T[]>(initial);\n\n const append = useCallback((...items: T[]): void => {\n setList((current) => [...current, ...items]);\n }, []);\n\n const prepend = useCallback((...items: T[]): void => {\n setList((current) => [...items, ...current]);\n }, []);\n\n const insert = useCallback((index: number, ...items: T[]): void => {\n setList((current) => [...current.slice(0, index), ...items, ...current.slice(index)]);\n }, []);\n\n const remove = useCallback((...indices: number[]): void => {\n const drop = new Set(indices);\n setList((current) => current.filter((_, index) => !drop.has(index)));\n }, []);\n\n const reorder = useCallback(({ from, to }: ReorderPayload): void => {\n setList((current) => {\n const next = [...current];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved);\n return next;\n });\n }, []);\n\n const setItem = useCallback((index: number, item: T): void => {\n setList((current) => current.map((value, i) => (i === index ? item : value)));\n }, []);\n\n const setState = useCallback((items: T[]): void => setList(items), []);\n\n const apply = useCallback((fn: (item: T, index: number) => T): void => {\n setList((current) => current.map(fn));\n }, []);\n\n const clear = useCallback((): void => setList([]), []);\n\n const handlers = useMemo<ListStateHandlers<T>>(\n () => ({\n append,\n prepend,\n insert,\n remove,\n reorder,\n setItem,\n setState,\n apply,\n clear,\n }),\n [append, prepend, insert, remove, reorder, setItem, setState, apply, clear],\n );\n\n return [list, handlers];\n}\n"],"mappings":"uBA0BA,SAAgB,EAAgB,EAAe,CAAC,EAAgC,CAC5E,GAAM,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAc,CAAO,EAEvC,GAAA,EAAS,EAAA,YAAA,EAAa,GAAG,IAAqB,CAChD,EAAS,GAAY,CAAC,GAAG,EAAS,GAAG,CAAK,CAAC,CAC/C,EAAG,CAAC,CAAC,EAEC,GAAA,EAAU,EAAA,YAAA,EAAa,GAAG,IAAqB,CACjD,EAAS,GAAY,CAAC,GAAG,EAAO,GAAG,CAAO,CAAC,CAC/C,EAAG,CAAC,CAAC,EAEC,GAAA,EAAS,EAAA,YAAA,EAAa,EAAe,GAAG,IAAqB,CAC/D,EAAS,GAAY,CAAC,GAAG,EAAQ,MAAM,EAAG,CAAK,EAAG,GAAG,EAAO,GAAG,EAAQ,MAAM,CAAK,CAAC,CAAC,CACxF,EAAG,CAAC,CAAC,EAEC,GAAA,EAAS,EAAA,YAAA,EAAa,GAAG,IAA4B,CACvD,IAAM,EAAO,IAAI,IAAI,CAAO,EAC5B,EAAS,GAAY,EAAQ,QAAQ,EAAG,IAAU,CAAC,EAAK,IAAI,CAAK,CAAC,CAAC,CACvE,EAAG,CAAC,CAAC,EAEC,GAAA,EAAU,EAAA,YAAA,EAAa,CAAE,OAAM,QAA+B,CAChE,EAAS,GAAY,CACjB,IAAM,EAAO,CAAC,GAAG,CAAO,EAClB,CAAC,GAAS,EAAK,OAAO,EAAM,CAAC,EAEnC,OADA,EAAK,OAAO,EAAI,EAAG,CAAK,EACjB,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEC,GAAA,EAAU,EAAA,YAAA,EAAa,EAAe,IAAkB,CAC1D,EAAS,GAAY,EAAQ,KAAK,EAAO,IAAO,IAAM,EAAQ,EAAO,CAAM,CAAC,CAChF,EAAG,CAAC,CAAC,EAEC,GAAA,EAAW,EAAA,YAAA,CAAa,GAAqB,EAAQ,CAAK,EAAG,CAAC,CAAC,EAE/D,GAAA,EAAQ,EAAA,YAAA,CAAa,GAA4C,CACnE,EAAS,GAAY,EAAQ,IAAI,CAAE,CAAC,CACxC,EAAG,CAAC,CAAC,EAEC,GAAA,EAAQ,EAAA,YAAA,KAAwB,EAAQ,CAAC,CAAC,EAAG,CAAC,CAAC,EAiBrD,MAAO,CAAC,GAAA,EAfS,EAAA,QAAA,MACN,CACH,SACA,UACA,SACA,SACA,UACA,UACA,WACA,QACA,OACJ,GACA,CAAC,EAAQ,EAAS,EAAQ,EAAQ,EAAS,EAAS,EAAU,EAAO,CAAK,CAGhE,CAAQ,CAC1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-local-storage.cjs","names":[],"sources":["../../src/hooks/use-local-storage.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\nexport type LocalStorageOptions<T> = {\n serialize?: (value: T) => string;\n deserialize?: (raw: string) => T;\n};\n\nconst defaultSerialize = JSON.stringify;\nconst defaultDeserialize = <T>(raw: string): T => JSON.parse(raw) as T;\n\n/**\n * State synced with `localStorage`. SSR-safe — initial render returns the\n * provided default; the stored value is hydrated after mount. Updates to the\n * same key in other tabs are picked up via the `storage` event.\n *\n * @tempest-limits empty-catch — the three swallows here are the hook's contract.\n * A write that hits the quota (or Safari private mode) still updates React state,\n * so the session keeps working and only persistence is lost; a `storage` event\n * carrying a value this tab cannot deserialize is another tab's bug, and the\n * useful response is to keep the value already rendered rather than tear the\n * component down over a foreign write.\n *\n * @param key - localStorage key.\n * @param defaultValue - value used when nothing is stored or in SSR.\n * @param options - custom `serialize` / `deserialize` (default JSON).\n * @returns Tuple `[value, setValue, remove]`.\n */\nexport function useLocalStorage<T>(\n key: string,\n defaultValue: T,\n options: LocalStorageOptions<T> = {},\n): [T, (value: T | ((prev: T) => T)) => void, () => void] {\n const serialize = options.serialize ?? defaultSerialize;\n const deserialize = options.deserialize ?? defaultDeserialize;\n\n const read = useCallback((): T => {\n if (typeof window === \"undefined\") return defaultValue;\n try {\n const raw = window.localStorage.getItem(key);\n if (raw === null) return defaultValue;\n return deserialize(raw);\n } catch {\n return defaultValue;\n }\n }, [key, defaultValue, deserialize]);\n\n const [value, setStored] = useState<T>(read);\n\n useEffect(() => {\n setStored(read());\n }, [read]);\n\n const setValue = useCallback(\n (next: T | ((prev: T) => T)): void => {\n setStored((current) => {\n const resolved =\n typeof next === \"function\" ? (next as (prev: T) => T)(current) : next;\n try {\n if (typeof window !== \"undefined\") {\n window.localStorage.setItem(key, serialize(resolved));\n }\n } catch {\n /* empty */\n }\n return resolved;\n });\n },\n [key, serialize],\n );\n\n const remove = useCallback((): void => {\n try {\n if (typeof window !== \"undefined\") {\n window.localStorage.removeItem(key);\n }\n } catch {\n /* empty */\n }\n setStored(defaultValue);\n }, [key, defaultValue]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const onStorage = (event: StorageEvent): void => {\n if (event.key !== key) return;\n if (event.newValue === null) {\n setStored(defaultValue);\n return;\n }\n try {\n setStored(deserialize(event.newValue));\n } catch {\n /* empty */\n }\n };\n window.addEventListener(\"storage\", onStorage);\n return () => window.removeEventListener(\"storage\", onStorage);\n }, [key, defaultValue, deserialize]);\n\n return [value, setValue, remove];\n}\n"],"mappings":"uBAOA,IAAM,EAAmB,KAAK,UACxB,EAAyB,GAAmB,KAAK,MAAM,CAAG,EAmBhE,SAAgB,EACZ,EACA,EACA,EAAkC,CAAC,EACmB,CACtD,IAAM,EAAY,EAAQ,WAAa,EACjC,EAAc,EAAQ,aAAe,EAErC,GAAA,EAAA,EAAA,YAAA,KAA4B,CAC9B,GAAI,OAAO,OAAW,IAAa,OAAO,EAC1C,GAAI,CACA,IAAM,EAAM,OAAO,aAAa,QAAQ,CAAG,EAE3C,OADI,IAAQ,KAAa,EAClB,EAAY,CAAG,CAC1B,MAAQ,CACJ,OAAO,CACX,CACJ,EAAG,CAAC,EAAK,EAAc,CAAW,CAAC,EAE7B,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAAyB,CAAI,GAE3C,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAU,EAAK,CAAC,CACpB,EAAG,CAAC,CAAI,CAAC,EAET,IAAM,GAAA,EAAA,EAAA,YAAA,CACD,GAAqC,CAClC,EAAW,GAAY,CACnB,IAAM,EACF,OAAO,GAAS,WAAc,EAAwB,CAAO,EAAI,EACrE,GAAI,CACI,OAAO,OAAW,KAClB,OAAO,aAAa,QAAQ,EAAK,EAAU,CAAQ,CAAC,CAE5D,MAAQ,CAER,CACA,OAAO,CACX,CAAC,CACL,EACA,CAAC,EAAK,CAAS,CACnB,EAEM,GAAA,EAAA,EAAA,YAAA,KAAiC,CACnC,GAAI,CACI,OAAO,OAAW,KAClB,OAAO,aAAa,WAAW,CAAG,CAE1C,MAAQ,CAER,CACA,EAAU,CAAY,CAC1B,EAAG,CAAC,EAAK,CAAY,CAAC,EAoBtB,OAlBA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,EAAa,GAA8B,CACzC,KAAM,MAAQ,EAClB,IAAI,EAAM,WAAa,KAAM,CACzB,EAAU,CAAY,EACtB,MACJ,CACA,GAAI,CACA,EAAU,EAAY,EAAM,QAAQ,CAAC,CACzC,MAAQ,CAER,CALA,CAMJ,EAEA,OADA,OAAO,iBAAiB,UAAW,CAAS,MAC/B,OAAO,oBAAoB,UAAW,CAAS,CAChE,EAAG,CAAC,EAAK,EAAc,CAAW,CAAC,EAE5B,CAAC,EAAO,EAAU,CAAM,CACnC"}
1
+ {"version":3,"file":"use-local-storage.cjs","names":[],"sources":["../../src/hooks/use-local-storage.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\nexport type LocalStorageOptions<T> = {\n serialize?: (value: T) => string;\n deserialize?: (raw: string) => T;\n};\n\nconst defaultSerialize = JSON.stringify;\nconst defaultDeserialize = <T>(raw: string): T => JSON.parse(raw) as T;\n\n/**\n * State synced with `localStorage`. SSR-safe — initial render returns the\n * provided default; the stored value is hydrated after mount. Updates to the\n * same key in other tabs are picked up via the `storage` event.\n *\n * @tempest-limits empty-catch — the three swallows here are the hook's contract.\n * A write that hits the quota (or Safari private mode) still updates React state,\n * so the session keeps working and only persistence is lost; a `storage` event\n * carrying a value this tab cannot deserialize is another tab's bug, and the\n * useful response is to keep the value already rendered rather than tear the\n * component down over a foreign write.\n *\n * @param key - localStorage key.\n * @param defaultValue - value used when nothing is stored or in SSR.\n * @param options - custom `serialize` / `deserialize` (default JSON).\n * @returns Tuple `[value, setValue, remove]`.\n */\nexport function useLocalStorage<T>(\n key: string,\n defaultValue: T,\n options: LocalStorageOptions<T> = {},\n): [T, (value: T | ((prev: T) => T)) => void, () => void] {\n const serialize = options.serialize ?? defaultSerialize;\n const deserialize = options.deserialize ?? defaultDeserialize;\n\n const read = useCallback((): T => {\n if (typeof window === \"undefined\") return defaultValue;\n try {\n const raw = window.localStorage.getItem(key);\n if (raw === null) return defaultValue;\n return deserialize(raw);\n } catch {\n return defaultValue;\n }\n }, [key, defaultValue, deserialize]);\n\n const [value, setStored] = useState<T>(read);\n\n useEffect(() => {\n setStored(read());\n }, [read]);\n\n const setValue = useCallback(\n (next: T | ((prev: T) => T)): void => {\n setStored((current) => {\n const resolved =\n typeof next === \"function\" ? (next as (prev: T) => T)(current) : next;\n try {\n if (typeof window !== \"undefined\") {\n window.localStorage.setItem(key, serialize(resolved));\n }\n } catch {\n /* empty */\n }\n return resolved;\n });\n },\n [key, serialize],\n );\n\n const remove = useCallback((): void => {\n try {\n if (typeof window !== \"undefined\") {\n window.localStorage.removeItem(key);\n }\n } catch {\n /* empty */\n }\n setStored(defaultValue);\n }, [key, defaultValue]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const onStorage = (event: StorageEvent): void => {\n if (event.key !== key) return;\n if (event.newValue === null) {\n setStored(defaultValue);\n return;\n }\n try {\n setStored(deserialize(event.newValue));\n } catch {\n /* empty */\n }\n };\n window.addEventListener(\"storage\", onStorage);\n return () => window.removeEventListener(\"storage\", onStorage);\n }, [key, defaultValue, deserialize]);\n\n return [value, setValue, remove];\n}\n"],"mappings":"uBAOA,IAAM,EAAmB,KAAK,UACxB,EAAyB,GAAmB,KAAK,MAAM,CAAG,EAmBhE,SAAgB,EACZ,EACA,EACA,EAAkC,CAAC,EACmB,CACtD,IAAM,EAAY,EAAQ,WAAa,EACjC,EAAc,EAAQ,aAAe,EAErC,GAAA,EAAO,EAAA,YAAA,KAAqB,CAC9B,GAAI,OAAO,OAAW,IAAa,OAAO,EAC1C,GAAI,CACA,IAAM,EAAM,OAAO,aAAa,QAAQ,CAAG,EAE3C,OADI,IAAQ,KAAa,EAClB,EAAY,CAAG,CAC1B,MAAQ,CACJ,OAAO,CACX,CACJ,EAAG,CAAC,EAAK,EAAc,CAAW,CAAC,EAE7B,CAAC,EAAO,IAAA,EAAa,EAAA,SAAA,CAAY,CAAI,GAE3C,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAU,EAAK,CAAC,CACpB,EAAG,CAAC,CAAI,CAAC,EAET,IAAM,GAAA,EAAW,EAAA,YAAA,CACZ,GAAqC,CAClC,EAAW,GAAY,CACnB,IAAM,EACF,OAAO,GAAS,WAAc,EAAwB,CAAO,EAAI,EACrE,GAAI,CACI,OAAO,OAAW,KAClB,OAAO,aAAa,QAAQ,EAAK,EAAU,CAAQ,CAAC,CAE5D,MAAQ,CAER,CACA,OAAO,CACX,CAAC,CACL,EACA,CAAC,EAAK,CAAS,CACnB,EAEM,GAAA,EAAS,EAAA,YAAA,KAAwB,CACnC,GAAI,CACI,OAAO,OAAW,KAClB,OAAO,aAAa,WAAW,CAAG,CAE1C,MAAQ,CAER,CACA,EAAU,CAAY,CAC1B,EAAG,CAAC,EAAK,CAAY,CAAC,EAoBtB,OAlBA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,EAAa,GAA8B,CACzC,KAAM,MAAQ,EAClB,IAAI,EAAM,WAAa,KAAM,CACzB,EAAU,CAAY,EACtB,MACJ,CACA,GAAI,CACA,EAAU,EAAY,EAAM,QAAQ,CAAC,CACzC,MAAQ,CAER,CALA,CAMJ,EAEA,OADA,OAAO,iBAAiB,UAAW,CAAS,MAC/B,OAAO,oBAAoB,UAAW,CAAS,CAChE,EAAG,CAAC,EAAK,EAAc,CAAW,CAAC,EAE5B,CAAC,EAAO,EAAU,CAAM,CACnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-long-press-handlers.cjs","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":"uBAoEA,SAAgB,EACZ,EACA,EAAuC,CAAC,EACd,CAC1B,GAAM,CAAE,UAAU,IAAK,WAAW,IAAU,EACtC,GAAA,EAAA,EAAA,OAAA,CAAiC,IAAI,EACrC,GAAA,EAAA,EAAA,OAAA,CAA2B,EAAK,EAChC,GAAA,EAAA,EAAA,OAAA,CAAiC,CAAW,GAClD,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAY,QAAU,CAC1B,EAAG,CAAC,CAAW,CAAC,EAEhB,IAAM,GAAA,EAAA,EAAA,YAAA,KAAgC,CAC9B,EAAS,UAAY,OACrB,OAAO,aAAa,EAAS,OAAO,EACpC,EAAS,QAAU,KAE3B,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,KAAgC,CAC9B,IACJ,EAAS,QAAU,GACnB,EAAM,EACN,EAAS,QAAU,OAAO,eAAiB,CACvC,EAAS,QAAU,GACnB,EAAY,QAAQ,CACxB,EAAG,CAAO,EACd,EAAG,CAAC,EAAU,EAAO,CAAO,CAAC,EAY7B,MAAO,CACH,YAAa,EACb,UAAW,EACX,aAAc,EACd,aAAc,EACd,WAAY,EACZ,YAAa,EACb,eAAA,EAAA,EAAA,YAAA,CAhBC,GAAiC,CAC1B,IACJ,EAAM,eAAe,EACrB,EAAS,QAAU,GACnB,EAAY,QAAQ,EACxB,EACA,CAAC,CAAQ,CAUT,EACA,iBAAoB,EAAS,OACjC,CACJ"}
1
+ {"version":3,"file":"use-long-press-handlers.cjs","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":"uBAoEA,SAAgB,EACZ,EACA,EAAuC,CAAC,EACd,CAC1B,GAAM,CAAE,UAAU,IAAK,WAAW,IAAU,EACtC,GAAA,EAAW,EAAA,OAAA,CAAsB,IAAI,EACrC,GAAA,EAAW,EAAA,OAAA,CAAgB,EAAK,EAChC,GAAA,EAAc,EAAA,OAAA,CAAmB,CAAW,GAClD,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAY,QAAU,CAC1B,EAAG,CAAC,CAAW,CAAC,EAEhB,IAAM,GAAA,EAAQ,EAAA,YAAA,KAAwB,CAC9B,EAAS,UAAY,OACrB,OAAO,aAAa,EAAS,OAAO,EACpC,EAAS,QAAU,KAE3B,EAAG,CAAC,CAAC,EAEC,GAAA,EAAQ,EAAA,YAAA,KAAwB,CAC9B,IACJ,EAAS,QAAU,GACnB,EAAM,EACN,EAAS,QAAU,OAAO,eAAiB,CACvC,EAAS,QAAU,GACnB,EAAY,QAAQ,CACxB,EAAG,CAAO,EACd,EAAG,CAAC,EAAU,EAAO,CAAO,CAAC,EAY7B,MAAO,CACH,YAAa,EACb,UAAW,EACX,aAAc,EACd,aAAc,EACd,WAAY,EACZ,YAAa,EACb,eAAA,EAjBkB,EAAA,YAAA,CACjB,GAAiC,CAC1B,IACJ,EAAM,eAAe,EACrB,EAAS,QAAU,GACnB,EAAY,QAAQ,EACxB,EACA,CAAC,CAAQ,CAUT,EACA,iBAAoB,EAAS,OACjC,CACJ"}
@@ -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 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"}
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,EAAQ,EAAA,OAAA,CAAO,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"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-map.cjs","names":[],"sources":["../../src/hooks/use-map.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\n\nexport interface UseMapResult<K, V> {\n map: ReadonlyMap<K, V>;\n set: (key: K, value: V) => void;\n delete: (key: K) => void;\n clear: () => void;\n get: (key: K) => V | undefined;\n has: (key: K) => boolean;\n size: number;\n}\n\n/**\n * Reactive `Map` wrapper. Mutating via `set` / `delete` / `clear` triggers a\n * re-render and yields a fresh `map` reference each time.\n *\n * @typeParam K - key type.\n * @typeParam V - value type.\n * @param initial - initial entries.\n * @returns `{ map, set, delete, clear, get, has, size }`.\n */\nexport function useMap<K, V>(initial?: Iterable<readonly [K, V]>): UseMapResult<K, V> {\n const [map, setMap] = useState<Map<K, V>>(() => new Map(initial));\n\n const set = useCallback((key: K, value: V): void => {\n setMap((current) => {\n const next = new Map(current);\n next.set(key, value);\n return next;\n });\n }, []);\n\n const remove = useCallback((key: K): void => {\n setMap((current) => {\n if (!current.has(key)) return current;\n const next = new Map(current);\n next.delete(key);\n return next;\n });\n }, []);\n\n const clear = useCallback((): void => {\n setMap((current) => (current.size === 0 ? current : new Map<K, V>()));\n }, []);\n\n const get = useCallback((key: K): V | undefined => map.get(key), [map]);\n const has = useCallback((key: K): boolean => map.has(key), [map]);\n\n return useMemo<UseMapResult<K, V>>(\n () => ({\n map,\n set,\n delete: remove,\n clear,\n get,\n has,\n size: map.size,\n }),\n [map, set, remove, clear, get, has],\n );\n}\n"],"mappings":"uBAqBA,SAAgB,EAAa,EAAyD,CAClF,GAAM,CAAC,EAAK,IAAA,EAAA,EAAA,SAAA,KAAoC,IAAI,IAAI,CAAO,CAAC,EAE1D,GAAA,EAAA,EAAA,YAAA,EAAmB,EAAQ,IAAmB,CAChD,EAAQ,GAAY,CAChB,IAAM,EAAO,IAAI,IAAI,CAAO,EAE5B,OADA,EAAK,IAAI,EAAK,CAAK,EACZ,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,CAAsB,GAAiB,CACzC,EAAQ,GAAY,CAChB,GAAI,CAAC,EAAQ,IAAI,CAAG,EAAG,OAAO,EAC9B,IAAM,EAAO,IAAI,IAAI,CAAO,EAE5B,OADA,EAAK,OAAO,CAAG,EACR,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,KAAgC,CAClC,EAAQ,GAAa,EAAQ,OAAS,EAAI,EAAU,IAAI,GAAY,CACxE,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,CAAmB,GAA0B,EAAI,IAAI,CAAG,EAAG,CAAC,CAAG,CAAC,EAChE,GAAA,EAAA,EAAA,YAAA,CAAmB,GAAoB,EAAI,IAAI,CAAG,EAAG,CAAC,CAAG,CAAC,EAEhE,OAAA,EAAA,EAAA,QAAA,MACW,CACH,MACA,MACA,OAAQ,EACR,QACA,MACA,MACA,KAAM,EAAI,IACd,GACA,CAAC,EAAK,EAAK,EAAQ,EAAO,EAAK,CAAG,CACtC,CACJ"}
1
+ {"version":3,"file":"use-map.cjs","names":[],"sources":["../../src/hooks/use-map.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\n\nexport interface UseMapResult<K, V> {\n map: ReadonlyMap<K, V>;\n set: (key: K, value: V) => void;\n delete: (key: K) => void;\n clear: () => void;\n get: (key: K) => V | undefined;\n has: (key: K) => boolean;\n size: number;\n}\n\n/**\n * Reactive `Map` wrapper. Mutating via `set` / `delete` / `clear` triggers a\n * re-render and yields a fresh `map` reference each time.\n *\n * @typeParam K - key type.\n * @typeParam V - value type.\n * @param initial - initial entries.\n * @returns `{ map, set, delete, clear, get, has, size }`.\n */\nexport function useMap<K, V>(initial?: Iterable<readonly [K, V]>): UseMapResult<K, V> {\n const [map, setMap] = useState<Map<K, V>>(() => new Map(initial));\n\n const set = useCallback((key: K, value: V): void => {\n setMap((current) => {\n const next = new Map(current);\n next.set(key, value);\n return next;\n });\n }, []);\n\n const remove = useCallback((key: K): void => {\n setMap((current) => {\n if (!current.has(key)) return current;\n const next = new Map(current);\n next.delete(key);\n return next;\n });\n }, []);\n\n const clear = useCallback((): void => {\n setMap((current) => (current.size === 0 ? current : new Map<K, V>()));\n }, []);\n\n const get = useCallback((key: K): V | undefined => map.get(key), [map]);\n const has = useCallback((key: K): boolean => map.has(key), [map]);\n\n return useMemo<UseMapResult<K, V>>(\n () => ({\n map,\n set,\n delete: remove,\n clear,\n get,\n has,\n size: map.size,\n }),\n [map, set, remove, clear, get, has],\n );\n}\n"],"mappings":"uBAqBA,SAAgB,EAAa,EAAyD,CAClF,GAAM,CAAC,EAAK,IAAA,EAAU,EAAA,SAAA,KAA0B,IAAI,IAAI,CAAO,CAAC,EAE1D,GAAA,EAAM,EAAA,YAAA,EAAa,EAAQ,IAAmB,CAChD,EAAQ,GAAY,CAChB,IAAM,EAAO,IAAI,IAAI,CAAO,EAE5B,OADA,EAAK,IAAI,EAAK,CAAK,EACZ,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEC,GAAA,EAAS,EAAA,YAAA,CAAa,GAAiB,CACzC,EAAQ,GAAY,CAChB,GAAI,CAAC,EAAQ,IAAI,CAAG,EAAG,OAAO,EAC9B,IAAM,EAAO,IAAI,IAAI,CAAO,EAE5B,OADA,EAAK,OAAO,CAAG,EACR,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEC,GAAA,EAAQ,EAAA,YAAA,KAAwB,CAClC,EAAQ,GAAa,EAAQ,OAAS,EAAI,EAAU,IAAI,GAAY,CACxE,EAAG,CAAC,CAAC,EAEC,GAAA,EAAM,EAAA,YAAA,CAAa,GAA0B,EAAI,IAAI,CAAG,EAAG,CAAC,CAAG,CAAC,EAChE,GAAA,EAAM,EAAA,YAAA,CAAa,GAAoB,EAAI,IAAI,CAAG,EAAG,CAAC,CAAG,CAAC,EAEhE,OAAA,EAAO,EAAA,QAAA,MACI,CACH,MACA,MACA,OAAQ,EACR,QACA,MACA,MACA,KAAM,EAAI,IACd,GACA,CAAC,EAAK,EAAK,EAAQ,EAAO,EAAK,CAAG,CACtC,CACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-media-devices.cjs","names":[],"sources":["../../src/hooks/use-media-devices.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/** One device the browser is willing to tell us about. */\nexport interface MediaDeviceOption {\n deviceId: string;\n /**\n * Human label, or `\"\"` until permission has been granted.\n *\n * See {@link UseMediaDevicesResult.labelsAvailable} — an empty label is not a\n * bug, it is the browser refusing to fingerprint the machine.\n */\n label: string;\n kind: MediaDeviceKind;\n groupId: string;\n}\n\n/** Value returned by {@link useMediaDevices}. */\nexport interface UseMediaDevicesResult {\n /** Every device, in the order the browser listed them. */\n devices: MediaDeviceOption[];\n /** Microphones and other audio sources. */\n audioInputs: MediaDeviceOption[];\n /** Speakers and headsets. Empty on browsers with no output routing (Safari, Firefox). */\n audioOutputs: MediaDeviceOption[];\n /** Cameras. */\n videoInputs: MediaDeviceOption[];\n /**\n * Whether labels are filled in.\n *\n * `false` means the list is real but anonymous — render a picker only after a\n * capture permission has been granted, or the user sees \"\" repeated N times.\n */\n labelsAvailable: boolean;\n /** `enumerateDevices` is unavailable in this browser. */\n supported: boolean;\n /** Re-enumerate. The hook already does this on `devicechange`. */\n refresh: () => void;\n}\n\nconst EMPTY: MediaDeviceOption[] = [];\n\n/**\n * List capture and playback devices, and keep the list fresh.\n *\n * Two things about `enumerateDevices` that decide how a picker must be built:\n *\n * 1. **Labels are gated behind permission.** Before the user grants a capture\n * permission, every `label` is `\"\"` — the list length and ids are real, the names\n * are not. A device picker rendered at that point is a column of blanks, so\n * `labelsAvailable` is exposed to gate it. Ask for the microphone first, then\n * show the picker.\n * 2. **The list changes while the page is open.** Plugging in a headset mid-recording\n * is the normal case, not an edge case, so the hook subscribes to `devicechange`\n * instead of enumerating once on mount.\n *\n * `audioOutputs` is empty on browsers with no output routing at all (Safari and\n * Firefox do not implement `setSinkId`); an empty array there means \"you cannot\n * offer this choice\", not \"no speakers\".\n *\n * @returns The device lists, whether labels are filled in, and a `refresh()`.\n *\n * @example\n * const { audioInputs, labelsAvailable } = useMediaDevices();\n * // ...after the mic permission is granted:\n * {labelsAvailable && <Select options={audioInputs.map((d) => ({ value: d.deviceId, label: d.label }))} />}\n */\nexport function useMediaDevices(): UseMediaDevicesResult {\n const [devices, setDevices] = useState<MediaDeviceOption[]>(EMPTY);\n const [supported, setSupported] = useState(false);\n const [token, setToken] = useState(0);\n\n const refresh = useCallback(() => setToken((value) => value + 1), []);\n\n useEffect(() => {\n let cancelled = false;\n\n if (\n typeof navigator === \"undefined\" ||\n !navigator.mediaDevices ||\n typeof navigator.mediaDevices.enumerateDevices !== \"function\"\n ) {\n setSupported(false);\n setDevices(EMPTY);\n return;\n }\n setSupported(true);\n const media = navigator.mediaDevices;\n\n async function read(): Promise<void> {\n try {\n const list = await media.enumerateDevices();\n if (cancelled) return;\n setDevices(\n list.map((device) => ({\n deviceId: device.deviceId,\n label: device.label,\n kind: device.kind,\n groupId: device.groupId,\n })),\n );\n } catch {\n if (!cancelled) setDevices(EMPTY);\n }\n }\n\n void read();\n const onChange = (): void => void read();\n media.addEventListener?.(\"devicechange\", onChange);\n\n return () => {\n cancelled = true;\n media.removeEventListener?.(\"devicechange\", onChange);\n };\n }, [token]);\n\n return {\n devices,\n audioInputs: devices.filter((device) => device.kind === \"audioinput\"),\n audioOutputs: devices.filter((device) => device.kind === \"audiooutput\"),\n videoInputs: devices.filter((device) => device.kind === \"videoinput\"),\n labelsAvailable: devices.length > 0 && devices.some((device) => device.label !== \"\"),\n supported,\n refresh,\n };\n}\n"],"mappings":"uBAuCA,IAAM,EAA6B,CAAC,EA2BpC,SAAgB,GAAyC,CACrD,GAAM,CAAC,EAAS,IAAA,EAAA,EAAA,SAAA,CAA4C,CAAK,EAC3D,CAAC,EAAW,IAAA,EAAA,EAAA,SAAA,CAAyB,EAAK,EAC1C,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAAqB,CAAC,EAE9B,GAAA,EAAA,EAAA,YAAA,KAA4B,EAAU,GAAU,EAAQ,CAAC,EAAG,CAAC,CAAC,EA4CpE,OA1CA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAI,EAAY,GAEhB,GACI,OAAO,UAAc,KACrB,CAAC,UAAU,cACX,OAAO,UAAU,aAAa,kBAAqB,WACrD,CACE,EAAa,EAAK,EAClB,EAAW,CAAK,EAChB,MACJ,CACA,EAAa,EAAI,EACjB,IAAM,EAAQ,UAAU,aAExB,eAAe,GAAsB,CACjC,GAAI,CACA,IAAM,EAAO,MAAM,EAAM,iBAAiB,EAC1C,GAAI,EAAW,OACf,EACI,EAAK,IAAK,IAAY,CAClB,SAAU,EAAO,SACjB,MAAO,EAAO,MACd,KAAM,EAAO,KACb,QAAS,EAAO,OACpB,EAAE,CACN,CACJ,MAAQ,CACC,GAAW,EAAW,CAAK,CACpC,CACJ,CAEA,EAAU,EACV,IAAM,MAAuB,KAAK,EAAK,EAGvC,OAFA,EAAM,mBAAmB,eAAgB,CAAQ,MAEpC,CACT,EAAY,GACZ,EAAM,sBAAsB,eAAgB,CAAQ,CACxD,CACJ,EAAG,CAAC,CAAK,CAAC,EAEH,CACH,UACA,YAAa,EAAQ,OAAQ,GAAW,EAAO,OAAS,YAAY,EACpE,aAAc,EAAQ,OAAQ,GAAW,EAAO,OAAS,aAAa,EACtE,YAAa,EAAQ,OAAQ,GAAW,EAAO,OAAS,YAAY,EACpE,gBAAiB,EAAQ,OAAS,GAAK,EAAQ,KAAM,GAAW,EAAO,QAAU,EAAE,EACnF,YACA,SACJ,CACJ"}
1
+ {"version":3,"file":"use-media-devices.cjs","names":[],"sources":["../../src/hooks/use-media-devices.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/** One device the browser is willing to tell us about. */\nexport interface MediaDeviceOption {\n deviceId: string;\n /**\n * Human label, or `\"\"` until permission has been granted.\n *\n * See {@link UseMediaDevicesResult.labelsAvailable} — an empty label is not a\n * bug, it is the browser refusing to fingerprint the machine.\n */\n label: string;\n kind: MediaDeviceKind;\n groupId: string;\n}\n\n/** Value returned by {@link useMediaDevices}. */\nexport interface UseMediaDevicesResult {\n /** Every device, in the order the browser listed them. */\n devices: MediaDeviceOption[];\n /** Microphones and other audio sources. */\n audioInputs: MediaDeviceOption[];\n /** Speakers and headsets. Empty on browsers with no output routing (Safari, Firefox). */\n audioOutputs: MediaDeviceOption[];\n /** Cameras. */\n videoInputs: MediaDeviceOption[];\n /**\n * Whether labels are filled in.\n *\n * `false` means the list is real but anonymous — render a picker only after a\n * capture permission has been granted, or the user sees \"\" repeated N times.\n */\n labelsAvailable: boolean;\n /** `enumerateDevices` is unavailable in this browser. */\n supported: boolean;\n /** Re-enumerate. The hook already does this on `devicechange`. */\n refresh: () => void;\n}\n\nconst EMPTY: MediaDeviceOption[] = [];\n\n/**\n * List capture and playback devices, and keep the list fresh.\n *\n * Two things about `enumerateDevices` that decide how a picker must be built:\n *\n * 1. **Labels are gated behind permission.** Before the user grants a capture\n * permission, every `label` is `\"\"` — the list length and ids are real, the names\n * are not. A device picker rendered at that point is a column of blanks, so\n * `labelsAvailable` is exposed to gate it. Ask for the microphone first, then\n * show the picker.\n * 2. **The list changes while the page is open.** Plugging in a headset mid-recording\n * is the normal case, not an edge case, so the hook subscribes to `devicechange`\n * instead of enumerating once on mount.\n *\n * `audioOutputs` is empty on browsers with no output routing at all (Safari and\n * Firefox do not implement `setSinkId`); an empty array there means \"you cannot\n * offer this choice\", not \"no speakers\".\n *\n * @returns The device lists, whether labels are filled in, and a `refresh()`.\n *\n * @example\n * const { audioInputs, labelsAvailable } = useMediaDevices();\n * // ...after the mic permission is granted:\n * {labelsAvailable && <Select options={audioInputs.map((d) => ({ value: d.deviceId, label: d.label }))} />}\n */\nexport function useMediaDevices(): UseMediaDevicesResult {\n const [devices, setDevices] = useState<MediaDeviceOption[]>(EMPTY);\n const [supported, setSupported] = useState(false);\n const [token, setToken] = useState(0);\n\n const refresh = useCallback(() => setToken((value) => value + 1), []);\n\n useEffect(() => {\n let cancelled = false;\n\n if (\n typeof navigator === \"undefined\" ||\n !navigator.mediaDevices ||\n typeof navigator.mediaDevices.enumerateDevices !== \"function\"\n ) {\n setSupported(false);\n setDevices(EMPTY);\n return;\n }\n setSupported(true);\n const media = navigator.mediaDevices;\n\n async function read(): Promise<void> {\n try {\n const list = await media.enumerateDevices();\n if (cancelled) return;\n setDevices(\n list.map((device) => ({\n deviceId: device.deviceId,\n label: device.label,\n kind: device.kind,\n groupId: device.groupId,\n })),\n );\n } catch {\n if (!cancelled) setDevices(EMPTY);\n }\n }\n\n void read();\n const onChange = (): void => void read();\n media.addEventListener?.(\"devicechange\", onChange);\n\n return () => {\n cancelled = true;\n media.removeEventListener?.(\"devicechange\", onChange);\n };\n }, [token]);\n\n return {\n devices,\n audioInputs: devices.filter((device) => device.kind === \"audioinput\"),\n audioOutputs: devices.filter((device) => device.kind === \"audiooutput\"),\n videoInputs: devices.filter((device) => device.kind === \"videoinput\"),\n labelsAvailable: devices.length > 0 && devices.some((device) => device.label !== \"\"),\n supported,\n refresh,\n };\n}\n"],"mappings":"uBAuCA,IAAM,EAA6B,CAAC,EA2BpC,SAAgB,GAAyC,CACrD,GAAM,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAA8B,CAAK,EAC3D,CAAC,EAAW,IAAA,EAAgB,EAAA,SAAA,CAAS,EAAK,EAC1C,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAS,CAAC,EAE9B,GAAA,EAAU,EAAA,YAAA,KAAkB,EAAU,GAAU,EAAQ,CAAC,EAAG,CAAC,CAAC,EA4CpE,OA1CA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAI,EAAY,GAEhB,GACI,OAAO,UAAc,KACrB,CAAC,UAAU,cACX,OAAO,UAAU,aAAa,kBAAqB,WACrD,CACE,EAAa,EAAK,EAClB,EAAW,CAAK,EAChB,MACJ,CACA,EAAa,EAAI,EACjB,IAAM,EAAQ,UAAU,aAExB,eAAe,GAAsB,CACjC,GAAI,CACA,IAAM,EAAO,MAAM,EAAM,iBAAiB,EAC1C,GAAI,EAAW,OACf,EACI,EAAK,IAAK,IAAY,CAClB,SAAU,EAAO,SACjB,MAAO,EAAO,MACd,KAAM,EAAO,KACb,QAAS,EAAO,OACpB,EAAE,CACN,CACJ,MAAQ,CACC,GAAW,EAAW,CAAK,CACpC,CACJ,CAEA,EAAU,EACV,IAAM,MAAuB,KAAK,EAAK,EAGvC,OAFA,EAAM,mBAAmB,eAAgB,CAAQ,MAEpC,CACT,EAAY,GACZ,EAAM,sBAAsB,eAAgB,CAAQ,CACxD,CACJ,EAAG,CAAC,CAAK,CAAC,EAEH,CACH,UACA,YAAa,EAAQ,OAAQ,GAAW,EAAO,OAAS,YAAY,EACpE,aAAc,EAAQ,OAAQ,GAAW,EAAO,OAAS,aAAa,EACtE,YAAa,EAAQ,OAAQ,GAAW,EAAO,OAAS,YAAY,EACpE,gBAAiB,EAAQ,OAAS,GAAK,EAAQ,KAAM,GAAW,EAAO,QAAU,EAAE,EACnF,YACA,SACJ,CACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-media-permission.cjs","names":[],"sources":["../../src/hooks/use-media-permission.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/** Which capture permission to observe. */\nexport type MediaPermissionName = \"microphone\" | \"camera\";\n\n/**\n * Permission state, including the two cases the browser prompt cannot tell you\n * apart on its own.\n *\n * - `\"unknown\"` — the Permissions API is unavailable (Safari does not report\n * `microphone`), so the only way to learn the answer is to ask for the device.\n * - `\"prompt\"` — never asked. Asking now shows the browser prompt.\n * - `\"granted\"` / `\"denied\"` — settled. `\"denied\"` is **sticky**: calling\n * `getUserMedia` again does not re-prompt, it rejects immediately.\n */\nexport type MediaPermissionState = \"unknown\" | \"prompt\" | \"granted\" | \"denied\";\n\n/** Value returned by {@link useMediaPermission}. */\nexport interface UseMediaPermissionResult {\n /** Current state. Updates live when the user changes it in browser settings. */\n state: MediaPermissionState;\n /** Whether the Permissions API could answer at all. */\n supported: boolean;\n /** Re-read the permission. Rarely needed — the hook subscribes to changes. */\n refresh: () => void;\n}\n\n/**\n * Read a capture permission **without triggering the prompt**.\n *\n * This is the piece that makes a good permission flow possible. `getUserMedia` is\n * the only way to *get* a device, but calling it is also the only way to *ask*, and\n * a prompt fired on page load — before the user has pressed anything — is the\n * single most reliable way to earn a permanent \"Block\". Reading the state first\n * lets a page explain why it needs the microphone, and only then ask.\n *\n * It also separates \"never asked\" from \"denied\", which matters because they need\n * opposite UI: `\"prompt\"` gets a button, `\"denied\"` gets instructions for the\n * browser's site settings, since no amount of clicking will re-prompt.\n *\n * Safari does not expose `microphone` to the Permissions API and throws on the\n * query, which surfaces as `state: \"unknown\"` and `supported: false` — treat that\n * as \"you will have to ask to find out\", not as an error.\n *\n * @param name - Which permission to observe.\n * @returns The live state, whether it could be read, and a manual `refresh()`.\n *\n * @example\n * const { state } = useMediaPermission(\"microphone\");\n * if (state === \"denied\") return <p>Libere o microfone nas configurações do site.</p>;\n * return <button onClick={start}>Gravar</button>;\n */\nexport function useMediaPermission(name: MediaPermissionName): UseMediaPermissionResult {\n const [state, setState] = useState<MediaPermissionState>(\"unknown\");\n const [supported, setSupported] = useState(false);\n const [token, setToken] = useState(0);\n\n const refresh = useCallback(() => setToken((value) => value + 1), []);\n\n useEffect(() => {\n let cancelled = false;\n let status: PermissionStatus | null = null;\n const onChange = (): void => {\n if (!cancelled && status) setState(status.state as MediaPermissionState);\n };\n\n async function read(): Promise<void> {\n if (typeof navigator === \"undefined\" || !navigator.permissions?.query) {\n if (!cancelled) {\n setSupported(false);\n setState(\"unknown\");\n }\n return;\n }\n try {\n status = await navigator.permissions.query({\n name: name as PermissionName,\n });\n if (cancelled) return;\n setSupported(true);\n setState(status.state as MediaPermissionState);\n status.addEventListener(\"change\", onChange);\n } catch {\n if (!cancelled) {\n setSupported(false);\n setState(\"unknown\");\n }\n }\n }\n\n void read();\n\n return () => {\n cancelled = true;\n status?.removeEventListener(\"change\", onChange);\n };\n }, [name, token]);\n\n return { state, supported, refresh };\n}\n"],"mappings":"uBAoDA,SAAgB,EAAmB,EAAqD,CACpF,GAAM,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAA2C,SAAS,EAC5D,CAAC,EAAW,IAAA,EAAA,EAAA,SAAA,CAAyB,EAAK,EAC1C,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAAqB,CAAC,EAE9B,GAAA,EAAA,EAAA,YAAA,KAA4B,EAAU,GAAU,EAAQ,CAAC,EAAG,CAAC,CAAC,EAyCpE,OAvCA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAI,EAAY,GACZ,EAAkC,KAChC,MAAuB,CACrB,CAAC,GAAa,GAAQ,EAAS,EAAO,KAA6B,CAC3E,EAEA,eAAe,GAAsB,CACjC,GAAI,OAAO,UAAc,KAAe,CAAC,UAAU,aAAa,MAAO,CAC9D,IACD,EAAa,EAAK,EAClB,EAAS,SAAS,GAEtB,MACJ,CACA,GAAI,CAIA,GAHA,EAAS,MAAM,UAAU,YAAY,MAAM,CACjC,MACV,CAAC,EACG,EAAW,OACf,EAAa,EAAI,EACjB,EAAS,EAAO,KAA6B,EAC7C,EAAO,iBAAiB,SAAU,CAAQ,CAC9C,MAAQ,CACC,IACD,EAAa,EAAK,EAClB,EAAS,SAAS,EAE1B,CACJ,CAIA,OAFA,EAAU,MAEG,CACT,EAAY,GACZ,GAAQ,oBAAoB,SAAU,CAAQ,CAClD,CACJ,EAAG,CAAC,EAAM,CAAK,CAAC,EAET,CAAE,QAAO,YAAW,SAAQ,CACvC"}
1
+ {"version":3,"file":"use-media-permission.cjs","names":[],"sources":["../../src/hooks/use-media-permission.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/** Which capture permission to observe. */\nexport type MediaPermissionName = \"microphone\" | \"camera\";\n\n/**\n * Permission state, including the two cases the browser prompt cannot tell you\n * apart on its own.\n *\n * - `\"unknown\"` — the Permissions API is unavailable (Safari does not report\n * `microphone`), so the only way to learn the answer is to ask for the device.\n * - `\"prompt\"` — never asked. Asking now shows the browser prompt.\n * - `\"granted\"` / `\"denied\"` — settled. `\"denied\"` is **sticky**: calling\n * `getUserMedia` again does not re-prompt, it rejects immediately.\n */\nexport type MediaPermissionState = \"unknown\" | \"prompt\" | \"granted\" | \"denied\";\n\n/** Value returned by {@link useMediaPermission}. */\nexport interface UseMediaPermissionResult {\n /** Current state. Updates live when the user changes it in browser settings. */\n state: MediaPermissionState;\n /** Whether the Permissions API could answer at all. */\n supported: boolean;\n /** Re-read the permission. Rarely needed — the hook subscribes to changes. */\n refresh: () => void;\n}\n\n/**\n * Read a capture permission **without triggering the prompt**.\n *\n * This is the piece that makes a good permission flow possible. `getUserMedia` is\n * the only way to *get* a device, but calling it is also the only way to *ask*, and\n * a prompt fired on page load — before the user has pressed anything — is the\n * single most reliable way to earn a permanent \"Block\". Reading the state first\n * lets a page explain why it needs the microphone, and only then ask.\n *\n * It also separates \"never asked\" from \"denied\", which matters because they need\n * opposite UI: `\"prompt\"` gets a button, `\"denied\"` gets instructions for the\n * browser's site settings, since no amount of clicking will re-prompt.\n *\n * Safari does not expose `microphone` to the Permissions API and throws on the\n * query, which surfaces as `state: \"unknown\"` and `supported: false` — treat that\n * as \"you will have to ask to find out\", not as an error.\n *\n * @param name - Which permission to observe.\n * @returns The live state, whether it could be read, and a manual `refresh()`.\n *\n * @example\n * const { state } = useMediaPermission(\"microphone\");\n * if (state === \"denied\") return <p>Libere o microfone nas configurações do site.</p>;\n * return <button onClick={start}>Gravar</button>;\n */\nexport function useMediaPermission(name: MediaPermissionName): UseMediaPermissionResult {\n const [state, setState] = useState<MediaPermissionState>(\"unknown\");\n const [supported, setSupported] = useState(false);\n const [token, setToken] = useState(0);\n\n const refresh = useCallback(() => setToken((value) => value + 1), []);\n\n useEffect(() => {\n let cancelled = false;\n let status: PermissionStatus | null = null;\n const onChange = (): void => {\n if (!cancelled && status) setState(status.state as MediaPermissionState);\n };\n\n async function read(): Promise<void> {\n if (typeof navigator === \"undefined\" || !navigator.permissions?.query) {\n if (!cancelled) {\n setSupported(false);\n setState(\"unknown\");\n }\n return;\n }\n try {\n status = await navigator.permissions.query({\n name: name as PermissionName,\n });\n if (cancelled) return;\n setSupported(true);\n setState(status.state as MediaPermissionState);\n status.addEventListener(\"change\", onChange);\n } catch {\n if (!cancelled) {\n setSupported(false);\n setState(\"unknown\");\n }\n }\n }\n\n void read();\n\n return () => {\n cancelled = true;\n status?.removeEventListener(\"change\", onChange);\n };\n }, [name, token]);\n\n return { state, supported, refresh };\n}\n"],"mappings":"uBAoDA,SAAgB,EAAmB,EAAqD,CACpF,GAAM,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAA+B,SAAS,EAC5D,CAAC,EAAW,IAAA,EAAgB,EAAA,SAAA,CAAS,EAAK,EAC1C,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAS,CAAC,EAE9B,GAAA,EAAU,EAAA,YAAA,KAAkB,EAAU,GAAU,EAAQ,CAAC,EAAG,CAAC,CAAC,EAyCpE,OAvCA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAI,EAAY,GACZ,EAAkC,KAChC,MAAuB,CACrB,CAAC,GAAa,GAAQ,EAAS,EAAO,KAA6B,CAC3E,EAEA,eAAe,GAAsB,CACjC,GAAI,OAAO,UAAc,KAAe,CAAC,UAAU,aAAa,MAAO,CAC9D,IACD,EAAa,EAAK,EAClB,EAAS,SAAS,GAEtB,MACJ,CACA,GAAI,CAIA,GAHA,EAAS,MAAM,UAAU,YAAY,MAAM,CACjC,MACV,CAAC,EACG,EAAW,OACf,EAAa,EAAI,EACjB,EAAS,EAAO,KAA6B,EAC7C,EAAO,iBAAiB,SAAU,CAAQ,CAC9C,MAAQ,CACC,IACD,EAAa,EAAK,EAClB,EAAS,SAAS,EAE1B,CACJ,CAIA,OAFA,EAAU,MAEG,CACT,EAAY,GACZ,GAAQ,oBAAoB,SAAU,CAAQ,CAClD,CACJ,EAAG,CAAC,EAAM,CAAK,CAAC,EAET,CAAE,QAAO,YAAW,SAAQ,CACvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-media-query.cjs","names":[],"sources":["../../src/hooks/use-media-query.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\n/**\n * Subscribe to a CSS media query and re-render on match changes.\n *\n * @param query - A standard CSS media query string, e.g. \"(max-width: 768px)\".\n * @returns True when the query matches.\n */\nexport function useMediaQuery(query: string): boolean {\n const [matches, setMatches] = useState<boolean>(() => {\n if (typeof window === \"undefined\") return false;\n return window.matchMedia(query).matches;\n });\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const list = window.matchMedia(query);\n const handler = (event: MediaQueryListEvent): void => setMatches(event.matches);\n setMatches(list.matches);\n list.addEventListener(\"change\", handler);\n return () => list.removeEventListener(\"change\", handler);\n }, [query]);\n\n return matches;\n}\n"],"mappings":"uBAQA,SAAgB,EAAc,EAAwB,CAClD,GAAM,CAAC,EAAS,IAAA,EAAA,EAAA,SAAA,KACR,OAAO,OAAW,IAAoB,GACnC,OAAO,WAAW,CAAK,CAAC,CAAC,OACnC,EAWD,OATA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,EAAO,OAAO,WAAW,CAAK,EAC9B,EAAW,GAAqC,EAAW,EAAM,OAAO,EAG9E,OAFA,EAAW,EAAK,OAAO,EACvB,EAAK,iBAAiB,SAAU,CAAO,MAC1B,EAAK,oBAAoB,SAAU,CAAO,CAC3D,EAAG,CAAC,CAAK,CAAC,EAEH,CACX"}
1
+ {"version":3,"file":"use-media-query.cjs","names":[],"sources":["../../src/hooks/use-media-query.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\n/**\n * Subscribe to a CSS media query and re-render on match changes.\n *\n * @param query - A standard CSS media query string, e.g. \"(max-width: 768px)\".\n * @returns True when the query matches.\n */\nexport function useMediaQuery(query: string): boolean {\n const [matches, setMatches] = useState<boolean>(() => {\n if (typeof window === \"undefined\") return false;\n return window.matchMedia(query).matches;\n });\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const list = window.matchMedia(query);\n const handler = (event: MediaQueryListEvent): void => setMatches(event.matches);\n setMatches(list.matches);\n list.addEventListener(\"change\", handler);\n return () => list.removeEventListener(\"change\", handler);\n }, [query]);\n\n return matches;\n}\n"],"mappings":"uBAQA,SAAgB,EAAc,EAAwB,CAClD,GAAM,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,KACtB,OAAO,OAAW,IAAoB,GACnC,OAAO,WAAW,CAAK,CAAC,CAAC,OACnC,EAWD,OATA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,EAAO,OAAO,WAAW,CAAK,EAC9B,EAAW,GAAqC,EAAW,EAAM,OAAO,EAG9E,OAFA,EAAW,EAAK,OAAO,EACvB,EAAK,iBAAiB,SAAU,CAAO,MAC1B,EAAK,oBAAoB,SAAU,CAAO,CAC3D,EAAG,CAAC,CAAK,CAAC,EAEH,CACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-object-url.cjs","names":[],"sources":["../../src/hooks/use-object-url.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\n/**\n * Create an object URL for a `Blob` (or `File`) and revoke it automatically on\n * unmount or whenever the blob changes. Returns `null` for nullish input.\n *\n * @param blob - the blob to expose as an object URL, or `null`/`undefined`.\n * @returns The object URL string, or `null` when there is no blob.\n */\nexport function useObjectUrl(blob: Blob | null | undefined): string | null {\n const [url, setUrl] = useState<string | null>(null);\n\n useEffect(() => {\n if (!blob) {\n setUrl(null);\n return;\n }\n const next = URL.createObjectURL(blob);\n setUrl(next);\n return () => URL.revokeObjectURL(next);\n }, [blob]);\n\n return url;\n}\n"],"mappings":"uBASA,SAAgB,EAAa,EAA8C,CACvE,GAAM,CAAC,EAAK,IAAA,EAAA,EAAA,SAAA,CAAkC,IAAI,EAYlD,OAVA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,EAAM,CACP,EAAO,IAAI,EACX,MACJ,CACA,IAAM,EAAO,IAAI,gBAAgB,CAAI,EAErC,OADA,EAAO,CAAI,MACE,IAAI,gBAAgB,CAAI,CACzC,EAAG,CAAC,CAAI,CAAC,EAEF,CACX"}
1
+ {"version":3,"file":"use-object-url.cjs","names":[],"sources":["../../src/hooks/use-object-url.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\n/**\n * Create an object URL for a `Blob` (or `File`) and revoke it automatically on\n * unmount or whenever the blob changes. Returns `null` for nullish input.\n *\n * @param blob - the blob to expose as an object URL, or `null`/`undefined`.\n * @returns The object URL string, or `null` when there is no blob.\n */\nexport function useObjectUrl(blob: Blob | null | undefined): string | null {\n const [url, setUrl] = useState<string | null>(null);\n\n useEffect(() => {\n if (!blob) {\n setUrl(null);\n return;\n }\n const next = URL.createObjectURL(blob);\n setUrl(next);\n return () => URL.revokeObjectURL(next);\n }, [blob]);\n\n return url;\n}\n"],"mappings":"uBASA,SAAgB,EAAa,EAA8C,CACvE,GAAM,CAAC,EAAK,IAAA,EAAU,EAAA,SAAA,CAAwB,IAAI,EAYlD,OAVA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,EAAM,CACP,EAAO,IAAI,EACX,MACJ,CACA,IAAM,EAAO,IAAI,gBAAgB,CAAI,EAErC,OADA,EAAO,CAAI,MACE,IAAI,gBAAgB,CAAI,CACzC,EAAG,CAAC,CAAI,CAAC,EAEF,CACX"}
@@ -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 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"}
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,EAAgB,EAAA,SAAA,KAC9B,OAAO,UAAc,KAAqB,UAAU,MACxD,EACM,CAAC,EAAW,IAAA,EAAgB,EAAA,SAAA,CAAkB,EAAI,EAElD,GAAA,EAAa,EAAA,OAAA,CAAO,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"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-pagination.cjs","names":[],"sources":["../../src/hooks/use-pagination.ts"],"sourcesContent":["import { useCallback, useState } from \"react\";\n\nexport interface UsePaginationResult {\n page: number;\n size: number;\n setPage: (page: number) => void;\n setSize: (size: number) => void;\n reset: () => void;\n}\n\n/**\n * Manage page/size state for paginated lists. Reset goes back to page 1\n * without touching the page size.\n *\n * @param initialPage - Starting page (default 1).\n * @param initialSize - Starting page size (default 50).\n * @returns Pagination state and setters.\n */\nexport function usePagination(initialPage = 1, initialSize = 50): UsePaginationResult {\n const [page, setPage] = useState<number>(initialPage);\n const [size, setSize] = useState<number>(initialSize);\n\n const reset = useCallback(() => setPage(1), []);\n\n return { page, size, setPage, setSize, reset };\n}\n"],"mappings":"uBAkBA,SAAgB,EAAc,EAAc,EAAG,EAAc,GAAyB,CAClF,GAAM,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,CAA4B,CAAW,EAC9C,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,CAA4B,CAAW,EAIpD,MAAO,CAAE,OAAM,OAAM,UAAS,UAAS,OAAA,EAAA,EAAA,YAAA,KAFP,EAAQ,CAAC,EAAG,CAAC,CAEN,CAAM,CACjD"}
1
+ {"version":3,"file":"use-pagination.cjs","names":[],"sources":["../../src/hooks/use-pagination.ts"],"sourcesContent":["import { useCallback, useState } from \"react\";\n\nexport interface UsePaginationResult {\n page: number;\n size: number;\n setPage: (page: number) => void;\n setSize: (size: number) => void;\n reset: () => void;\n}\n\n/**\n * Manage page/size state for paginated lists. Reset goes back to page 1\n * without touching the page size.\n *\n * @param initialPage - Starting page (default 1).\n * @param initialSize - Starting page size (default 50).\n * @returns Pagination state and setters.\n */\nexport function usePagination(initialPage = 1, initialSize = 50): UsePaginationResult {\n const [page, setPage] = useState<number>(initialPage);\n const [size, setSize] = useState<number>(initialSize);\n\n const reset = useCallback(() => setPage(1), []);\n\n return { page, size, setPage, setSize, reset };\n}\n"],"mappings":"uBAkBA,SAAgB,EAAc,EAAc,EAAG,EAAc,GAAyB,CAClF,GAAM,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAiB,CAAW,EAC9C,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAiB,CAAW,EAIpD,MAAO,CAAE,OAAM,OAAM,UAAS,UAAS,OAAA,EAFzB,EAAA,YAAA,KAAkB,EAAQ,CAAC,EAAG,CAAC,CAEN,CAAM,CACjD"}
@@ -1 +1 @@
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
+ {"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,EAAM,EAAA,OAAA,CAAsB,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-queue.cjs","names":[],"sources":["../../src/hooks/use-queue.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\n\nexport interface UseQueueOptions<T> {\n initialValues?: T[];\n limit?: number;\n}\n\nexport interface UseQueueResult<T> {\n /** Items currently held within the queue (up to `limit`). */\n queue: T[];\n /** Append items; overflow beyond `limit` is held back, not dropped. */\n add: (...items: T[]) => void;\n /** Replace the held queue via a mapper over the current held items. */\n update: (fn: (state: T[]) => T[]) => void;\n /** Drop all currently held (visible) items, keeping any overflow. */\n cleanQueue: () => void;\n /** Number of visible items in the queue. */\n size: number;\n}\n\n/**\n * FIFO queue with an optional `limit`. When more items are added than `limit`\n * allows, the surplus is kept in an internal overflow buffer and surfaces into\n * `queue` as room frees up (e.g. after `cleanQueue`). Loosely mirrors Mantine's\n * `useQueue` shape.\n *\n * @typeParam T - element type.\n * @param options - `initialValues` and `limit` (default limit `Infinity`).\n * @returns `{ queue, add, update, cleanQueue, size }`.\n */\nexport function useQueue<T>(options: UseQueueOptions<T> = {}): UseQueueResult<T> {\n const { initialValues = [], limit = Infinity } = options;\n\n const [state, setState] = useState<{ queue: T[]; overflow: T[] }>(() => ({\n queue: initialValues.slice(0, limit),\n overflow: initialValues.slice(limit),\n }));\n\n const add = useCallback(\n (...items: T[]): void => {\n setState((current) => {\n const all = [...current.queue, ...current.overflow, ...items];\n return {\n queue: all.slice(0, limit),\n overflow: all.slice(limit),\n };\n });\n },\n [limit],\n );\n\n const update = useCallback(\n (fn: (queueState: T[]) => T[]): void => {\n setState((current) => {\n const all = [...fn(current.queue), ...current.overflow];\n return {\n queue: all.slice(0, limit),\n overflow: all.slice(limit),\n };\n });\n },\n [limit],\n );\n\n const cleanQueue = useCallback((): void => {\n setState((current) => ({\n queue: current.overflow.slice(0, limit),\n overflow: current.overflow.slice(limit),\n }));\n }, [limit]);\n\n return useMemo<UseQueueResult<T>>(\n () => ({\n queue: state.queue,\n add,\n update,\n cleanQueue,\n size: state.queue.length,\n }),\n [state.queue, add, update, cleanQueue],\n );\n}\n"],"mappings":"uBA8BA,SAAgB,EAAY,EAA8B,CAAC,EAAsB,CAC7E,GAAM,CAAE,gBAAgB,CAAC,EAAG,QAAQ,KAAa,EAE3C,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,MAA2D,CACrE,MAAO,EAAc,MAAM,EAAG,CAAK,EACnC,SAAU,EAAc,MAAM,CAAK,CACvC,EAAE,EAEI,GAAA,EAAA,EAAA,YAAA,EACD,GAAG,IAAqB,CACrB,EAAU,GAAY,CAClB,IAAM,EAAM,CAAC,GAAG,EAAQ,MAAO,GAAG,EAAQ,SAAU,GAAG,CAAK,EAC5D,MAAO,CACH,MAAO,EAAI,MAAM,EAAG,CAAK,EACzB,SAAU,EAAI,MAAM,CAAK,CAC7B,CACJ,CAAC,CACL,EACA,CAAC,CAAK,CACV,EAEM,GAAA,EAAA,EAAA,YAAA,CACD,GAAuC,CACpC,EAAU,GAAY,CAClB,IAAM,EAAM,CAAC,GAAG,EAAG,EAAQ,KAAK,EAAG,GAAG,EAAQ,QAAQ,EACtD,MAAO,CACH,MAAO,EAAI,MAAM,EAAG,CAAK,EACzB,SAAU,EAAI,MAAM,CAAK,CAC7B,CACJ,CAAC,CACL,EACA,CAAC,CAAK,CACV,EAEM,GAAA,EAAA,EAAA,YAAA,KAAqC,CACvC,EAAU,IAAa,CACnB,MAAO,EAAQ,SAAS,MAAM,EAAG,CAAK,EACtC,SAAU,EAAQ,SAAS,MAAM,CAAK,CAC1C,EAAE,CACN,EAAG,CAAC,CAAK,CAAC,EAEV,OAAA,EAAA,EAAA,QAAA,MACW,CACH,MAAO,EAAM,MACb,MACA,SACA,aACA,KAAM,EAAM,MAAM,MACtB,GACA,CAAC,EAAM,MAAO,EAAK,EAAQ,CAAU,CACzC,CACJ"}
1
+ {"version":3,"file":"use-queue.cjs","names":[],"sources":["../../src/hooks/use-queue.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\n\nexport interface UseQueueOptions<T> {\n initialValues?: T[];\n limit?: number;\n}\n\nexport interface UseQueueResult<T> {\n /** Items currently held within the queue (up to `limit`). */\n queue: T[];\n /** Append items; overflow beyond `limit` is held back, not dropped. */\n add: (...items: T[]) => void;\n /** Replace the held queue via a mapper over the current held items. */\n update: (fn: (state: T[]) => T[]) => void;\n /** Drop all currently held (visible) items, keeping any overflow. */\n cleanQueue: () => void;\n /** Number of visible items in the queue. */\n size: number;\n}\n\n/**\n * FIFO queue with an optional `limit`. When more items are added than `limit`\n * allows, the surplus is kept in an internal overflow buffer and surfaces into\n * `queue` as room frees up (e.g. after `cleanQueue`). Loosely mirrors Mantine's\n * `useQueue` shape.\n *\n * @typeParam T - element type.\n * @param options - `initialValues` and `limit` (default limit `Infinity`).\n * @returns `{ queue, add, update, cleanQueue, size }`.\n */\nexport function useQueue<T>(options: UseQueueOptions<T> = {}): UseQueueResult<T> {\n const { initialValues = [], limit = Infinity } = options;\n\n const [state, setState] = useState<{ queue: T[]; overflow: T[] }>(() => ({\n queue: initialValues.slice(0, limit),\n overflow: initialValues.slice(limit),\n }));\n\n const add = useCallback(\n (...items: T[]): void => {\n setState((current) => {\n const all = [...current.queue, ...current.overflow, ...items];\n return {\n queue: all.slice(0, limit),\n overflow: all.slice(limit),\n };\n });\n },\n [limit],\n );\n\n const update = useCallback(\n (fn: (queueState: T[]) => T[]): void => {\n setState((current) => {\n const all = [...fn(current.queue), ...current.overflow];\n return {\n queue: all.slice(0, limit),\n overflow: all.slice(limit),\n };\n });\n },\n [limit],\n );\n\n const cleanQueue = useCallback((): void => {\n setState((current) => ({\n queue: current.overflow.slice(0, limit),\n overflow: current.overflow.slice(limit),\n }));\n }, [limit]);\n\n return useMemo<UseQueueResult<T>>(\n () => ({\n queue: state.queue,\n add,\n update,\n cleanQueue,\n size: state.queue.length,\n }),\n [state.queue, add, update, cleanQueue],\n );\n}\n"],"mappings":"uBA8BA,SAAgB,EAAY,EAA8B,CAAC,EAAsB,CAC7E,GAAM,CAAE,gBAAgB,CAAC,EAAG,QAAQ,KAAa,EAE3C,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,MAA+C,CACrE,MAAO,EAAc,MAAM,EAAG,CAAK,EACnC,SAAU,EAAc,MAAM,CAAK,CACvC,EAAE,EAEI,GAAA,EAAM,EAAA,YAAA,EACP,GAAG,IAAqB,CACrB,EAAU,GAAY,CAClB,IAAM,EAAM,CAAC,GAAG,EAAQ,MAAO,GAAG,EAAQ,SAAU,GAAG,CAAK,EAC5D,MAAO,CACH,MAAO,EAAI,MAAM,EAAG,CAAK,EACzB,SAAU,EAAI,MAAM,CAAK,CAC7B,CACJ,CAAC,CACL,EACA,CAAC,CAAK,CACV,EAEM,GAAA,EAAS,EAAA,YAAA,CACV,GAAuC,CACpC,EAAU,GAAY,CAClB,IAAM,EAAM,CAAC,GAAG,EAAG,EAAQ,KAAK,EAAG,GAAG,EAAQ,QAAQ,EACtD,MAAO,CACH,MAAO,EAAI,MAAM,EAAG,CAAK,EACzB,SAAU,EAAI,MAAM,CAAK,CAC7B,CACJ,CAAC,CACL,EACA,CAAC,CAAK,CACV,EAEM,GAAA,EAAa,EAAA,YAAA,KAAwB,CACvC,EAAU,IAAa,CACnB,MAAO,EAAQ,SAAS,MAAM,EAAG,CAAK,EACtC,SAAU,EAAQ,SAAS,MAAM,CAAK,CAC1C,EAAE,CACN,EAAG,CAAC,CAAK,CAAC,EAEV,OAAA,EAAO,EAAA,QAAA,MACI,CACH,MAAO,EAAM,MACb,MACA,SACA,aACA,KAAM,EAAM,MAAM,MACtB,GACA,CAAC,EAAM,MAAO,EAAK,EAAQ,CAAU,CACzC,CACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-resize-observer.cjs","names":[],"sources":["../../src/hooks/use-resize-observer.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport interface ElementSize {\n width: number;\n height: number;\n}\n\n/**\n * Track size changes of a DOM element via `ResizeObserver`.\n * Returns `null` until the first measurement.\n */\nexport function useResizeObserver(ref: RefObject<Element | null>): ElementSize | null {\n const [size, setSize] = useState<ElementSize | null>(null);\n\n useEffect(() => {\n const target = ref.current;\n if (!target || typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (!entry) return;\n const box = entry.contentRect;\n setSize({ width: box.width, height: box.height });\n });\n\n observer.observe(target);\n return () => observer.disconnect();\n }, [ref]);\n\n return size;\n}\n"],"mappings":"uBAYA,SAAgB,EAAkB,EAAoD,CAClF,GAAM,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,CAAwC,IAAI,EAiBzD,OAfA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAM,EAAS,EAAI,QACnB,GAAI,CAAC,GAAU,OAAO,eAAmB,IAAa,OAEtD,IAAM,EAAW,IAAI,eAAgB,GAAY,CAC7C,IAAM,EAAQ,EAAQ,GACtB,GAAI,CAAC,EAAO,OACZ,IAAM,EAAM,EAAM,YAClB,EAAQ,CAAE,MAAO,EAAI,MAAO,OAAQ,EAAI,MAAO,CAAC,CACpD,CAAC,EAGD,OADA,EAAS,QAAQ,CAAM,MACV,EAAS,WAAW,CACrC,EAAG,CAAC,CAAG,CAAC,EAED,CACX"}
1
+ {"version":3,"file":"use-resize-observer.cjs","names":[],"sources":["../../src/hooks/use-resize-observer.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport interface ElementSize {\n width: number;\n height: number;\n}\n\n/**\n * Track size changes of a DOM element via `ResizeObserver`.\n * Returns `null` until the first measurement.\n */\nexport function useResizeObserver(ref: RefObject<Element | null>): ElementSize | null {\n const [size, setSize] = useState<ElementSize | null>(null);\n\n useEffect(() => {\n const target = ref.current;\n if (!target || typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (!entry) return;\n const box = entry.contentRect;\n setSize({ width: box.width, height: box.height });\n });\n\n observer.observe(target);\n return () => observer.disconnect();\n }, [ref]);\n\n return size;\n}\n"],"mappings":"uBAYA,SAAgB,EAAkB,EAAoD,CAClF,GAAM,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAA6B,IAAI,EAiBzD,OAfA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAM,EAAS,EAAI,QACnB,GAAI,CAAC,GAAU,OAAO,eAAmB,IAAa,OAEtD,IAAM,EAAW,IAAI,eAAgB,GAAY,CAC7C,IAAM,EAAQ,EAAQ,GACtB,GAAI,CAAC,EAAO,OACZ,IAAM,EAAM,EAAM,YAClB,EAAQ,CAAE,MAAO,EAAI,MAAO,OAAQ,EAAI,MAAO,CAAC,CACpD,CAAC,EAGD,OADA,EAAS,QAAQ,CAAM,MACV,EAAS,WAAW,CACrC,EAAG,CAAC,CAAG,CAAC,EAED,CACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-scroll-overflow.cjs","names":[],"sources":["../../src/hooks/use-scroll-overflow.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\n/** Which axis to watch for overflow. */\nexport type ScrollOverflowAxis = \"horizontal\" | \"vertical\" | \"both\";\n\n/**\n * Track whether an element's content currently overflows its box.\n *\n * The use this exists for is keyboard access. A scroll container holding no\n * focusable content is unreachable by keyboard: the user can see there is more\n * content past the edge and has no way to get to it, because focus never lands\n * anywhere the arrow keys would scroll. Giving the container `tabIndex={0}`\n * fixes it — but doing that unconditionally puts a tab stop on every such\n * container on the page, including the ones whose content fits and have nothing\n * to scroll. The stop is only wanted while the overflow is real, which is what\n * this reports. (It is also what axe checks as `scrollable-region-focusable`.)\n *\n * Both the container and its content are observed: content can outgrow a box\n * whose own dimensions never change, and a box can shrink around content that\n * never changes. Watching one alone misses half the transitions.\n *\n * A one-pixel difference is ignored — that is layout rounding, not overflow.\n *\n * @param ref - The scroll container.\n * @param axis - Which axis to measure. Defaults to `\"both\"`.\n * @returns `true` while the content is larger than the box on that axis.\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null);\n * const scrollable = useScrollOverflow(ref, \"horizontal\");\n *\n * <div\n * ref={ref}\n * tabIndex={scrollable ? 0 : undefined}\n * role={scrollable ? \"group\" : undefined}\n * aria-label={scrollable ? \"Tabela rolável\" : undefined}\n * >\n */\nexport function useScrollOverflow(\n ref: RefObject<HTMLElement | null>,\n axis: ScrollOverflowAxis = \"both\",\n): boolean {\n const [overflowing, setOverflowing] = useState(false);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const measure = () => {\n const horizontal = element.scrollWidth - element.clientWidth > 1;\n const vertical = element.scrollHeight - element.clientHeight > 1;\n if (axis === \"horizontal\") setOverflowing(horizontal);\n else if (axis === \"vertical\") setOverflowing(vertical);\n else setOverflowing(horizontal || vertical);\n };\n measure();\n\n if (typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver(measure);\n observer.observe(element);\n const content = element.firstElementChild;\n if (content) observer.observe(content);\n return () => observer.disconnect();\n }, [ref, axis]);\n\n return overflowing;\n}\n"],"mappings":"uBAuCA,SAAgB,EACZ,EACA,EAA2B,OACpB,CACP,GAAM,CAAC,EAAa,IAAA,EAAA,EAAA,SAAA,CAA2B,EAAK,EAwBpD,OAtBA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAM,EAAU,EAAI,QACpB,GAAI,CAAC,EAAS,OAEd,IAAM,MAAgB,CAClB,IAAM,EAAa,EAAQ,YAAc,EAAQ,YAAc,EACzD,EAAW,EAAQ,aAAe,EAAQ,aAAe,EACpC,EAAvB,IAAS,aAA6B,EACjC,IAAS,WAA2B,EACzB,GAAc,CAAQ,CAC9C,EAGA,GAFA,EAAQ,EAEJ,OAAO,eAAmB,IAAa,OAE3C,IAAM,EAAW,IAAI,eAAe,CAAO,EAC3C,EAAS,QAAQ,CAAO,EACxB,IAAM,EAAU,EAAQ,kBAExB,OADI,GAAS,EAAS,QAAQ,CAAO,MACxB,EAAS,WAAW,CACrC,EAAG,CAAC,EAAK,CAAI,CAAC,EAEP,CACX"}
1
+ {"version":3,"file":"use-scroll-overflow.cjs","names":[],"sources":["../../src/hooks/use-scroll-overflow.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\n/** Which axis to watch for overflow. */\nexport type ScrollOverflowAxis = \"horizontal\" | \"vertical\" | \"both\";\n\n/**\n * Track whether an element's content currently overflows its box.\n *\n * The use this exists for is keyboard access. A scroll container holding no\n * focusable content is unreachable by keyboard: the user can see there is more\n * content past the edge and has no way to get to it, because focus never lands\n * anywhere the arrow keys would scroll. Giving the container `tabIndex={0}`\n * fixes it — but doing that unconditionally puts a tab stop on every such\n * container on the page, including the ones whose content fits and have nothing\n * to scroll. The stop is only wanted while the overflow is real, which is what\n * this reports. (It is also what axe checks as `scrollable-region-focusable`.)\n *\n * Both the container and its content are observed: content can outgrow a box\n * whose own dimensions never change, and a box can shrink around content that\n * never changes. Watching one alone misses half the transitions.\n *\n * A one-pixel difference is ignored — that is layout rounding, not overflow.\n *\n * @param ref - The scroll container.\n * @param axis - Which axis to measure. Defaults to `\"both\"`.\n * @returns `true` while the content is larger than the box on that axis.\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null);\n * const scrollable = useScrollOverflow(ref, \"horizontal\");\n *\n * <div\n * ref={ref}\n * tabIndex={scrollable ? 0 : undefined}\n * role={scrollable ? \"group\" : undefined}\n * aria-label={scrollable ? \"Tabela rolável\" : undefined}\n * >\n */\nexport function useScrollOverflow(\n ref: RefObject<HTMLElement | null>,\n axis: ScrollOverflowAxis = \"both\",\n): boolean {\n const [overflowing, setOverflowing] = useState(false);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const measure = () => {\n const horizontal = element.scrollWidth - element.clientWidth > 1;\n const vertical = element.scrollHeight - element.clientHeight > 1;\n if (axis === \"horizontal\") setOverflowing(horizontal);\n else if (axis === \"vertical\") setOverflowing(vertical);\n else setOverflowing(horizontal || vertical);\n };\n measure();\n\n if (typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver(measure);\n observer.observe(element);\n const content = element.firstElementChild;\n if (content) observer.observe(content);\n return () => observer.disconnect();\n }, [ref, axis]);\n\n return overflowing;\n}\n"],"mappings":"uBAuCA,SAAgB,EACZ,EACA,EAA2B,OACpB,CACP,GAAM,CAAC,EAAa,IAAA,EAAkB,EAAA,SAAA,CAAS,EAAK,EAwBpD,OAtBA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAM,EAAU,EAAI,QACpB,GAAI,CAAC,EAAS,OAEd,IAAM,MAAgB,CAClB,IAAM,EAAa,EAAQ,YAAc,EAAQ,YAAc,EACzD,EAAW,EAAQ,aAAe,EAAQ,aAAe,EACpC,EAAvB,IAAS,aAA6B,EACjC,IAAS,WAA2B,EACzB,GAAc,CAAQ,CAC9C,EAGA,GAFA,EAAQ,EAEJ,OAAO,eAAmB,IAAa,OAE3C,IAAM,EAAW,IAAI,eAAe,CAAO,EAC3C,EAAS,QAAQ,CAAO,EACxB,IAAM,EAAU,EAAQ,kBAExB,OADI,GAAS,EAAS,QAAQ,CAAO,MACxB,EAAS,WAAW,CACrC,EAAG,CAAC,EAAK,CAAI,CAAC,EAEP,CACX"}
@@ -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 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"}
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,EAAsB,EAAA,SAAA,CAAkB,EAAK,EAC/D,CAAC,EAAc,IAAA,EAAmB,EAAA,SAAA,CAA2C,IAAI,EACjF,GAAA,EAAa,EAAA,OAAA,CAA6B,IAAI,EAE9C,GAAA,EAAa,EAAA,OAAA,CAAO,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,EAZN,EAAA,YAAA,KAAkB,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 +1 @@
1
- {"version":3,"file":"use-set.cjs","names":[],"sources":["../../src/hooks/use-set.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\n\nexport interface UseSetResult<T> {\n set: ReadonlySet<T>;\n add: (value: T) => void;\n delete: (value: T) => void;\n clear: () => void;\n has: (value: T) => boolean;\n toggle: (value: T) => void;\n size: number;\n}\n\n/**\n * Reactive `Set` wrapper. Mutating via `add` / `delete` / `clear` / `toggle`\n * triggers a re-render and yields a fresh `set` reference each time.\n *\n * @typeParam T - element type.\n * @param initial - initial values.\n * @returns `{ set, add, delete, clear, has, toggle, size }`.\n */\nexport function useSet<T>(initial?: Iterable<T>): UseSetResult<T> {\n const [set, setSet] = useState<Set<T>>(() => new Set(initial));\n\n const add = useCallback((value: T): void => {\n setSet((current) => {\n if (current.has(value)) return current;\n const next = new Set(current);\n next.add(value);\n return next;\n });\n }, []);\n\n const remove = useCallback((value: T): void => {\n setSet((current) => {\n if (!current.has(value)) return current;\n const next = new Set(current);\n next.delete(value);\n return next;\n });\n }, []);\n\n const clear = useCallback((): void => {\n setSet((current) => (current.size === 0 ? current : new Set<T>()));\n }, []);\n\n const has = useCallback((value: T): boolean => set.has(value), [set]);\n\n const toggle = useCallback((value: T): void => {\n setSet((current) => {\n const next = new Set(current);\n if (next.has(value)) next.delete(value);\n else next.add(value);\n return next;\n });\n }, []);\n\n return useMemo<UseSetResult<T>>(\n () => ({\n set,\n add,\n delete: remove,\n clear,\n has,\n toggle,\n size: set.size,\n }),\n [set, add, remove, clear, has, toggle],\n );\n}\n"],"mappings":"uBAoBA,SAAgB,EAAU,EAAwC,CAC9D,GAAM,CAAC,EAAK,IAAA,EAAA,EAAA,SAAA,KAAiC,IAAI,IAAI,CAAO,CAAC,EAEvD,GAAA,EAAA,EAAA,YAAA,CAAmB,GAAmB,CACxC,EAAQ,GAAY,CAChB,GAAI,EAAQ,IAAI,CAAK,EAAG,OAAO,EAC/B,IAAM,EAAO,IAAI,IAAI,CAAO,EAE5B,OADA,EAAK,IAAI,CAAK,EACP,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,CAAsB,GAAmB,CAC3C,EAAQ,GAAY,CAChB,GAAI,CAAC,EAAQ,IAAI,CAAK,EAAG,OAAO,EAChC,IAAM,EAAO,IAAI,IAAI,CAAO,EAE5B,OADA,EAAK,OAAO,CAAK,EACV,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,KAAgC,CAClC,EAAQ,GAAa,EAAQ,OAAS,EAAI,EAAU,IAAI,GAAS,CACrE,EAAG,CAAC,CAAC,EAEC,GAAA,EAAA,EAAA,YAAA,CAAmB,GAAsB,EAAI,IAAI,CAAK,EAAG,CAAC,CAAG,CAAC,EAE9D,GAAA,EAAA,EAAA,YAAA,CAAsB,GAAmB,CAC3C,EAAQ,GAAY,CAChB,IAAM,EAAO,IAAI,IAAI,CAAO,EAG5B,OAFI,EAAK,IAAI,CAAK,EAAG,EAAK,OAAO,CAAK,EACjC,EAAK,IAAI,CAAK,EACZ,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEL,OAAA,EAAA,EAAA,QAAA,MACW,CACH,MACA,MACA,OAAQ,EACR,QACA,MACA,SACA,KAAM,EAAI,IACd,GACA,CAAC,EAAK,EAAK,EAAQ,EAAO,EAAK,CAAM,CACzC,CACJ"}
1
+ {"version":3,"file":"use-set.cjs","names":[],"sources":["../../src/hooks/use-set.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\n\nexport interface UseSetResult<T> {\n set: ReadonlySet<T>;\n add: (value: T) => void;\n delete: (value: T) => void;\n clear: () => void;\n has: (value: T) => boolean;\n toggle: (value: T) => void;\n size: number;\n}\n\n/**\n * Reactive `Set` wrapper. Mutating via `add` / `delete` / `clear` / `toggle`\n * triggers a re-render and yields a fresh `set` reference each time.\n *\n * @typeParam T - element type.\n * @param initial - initial values.\n * @returns `{ set, add, delete, clear, has, toggle, size }`.\n */\nexport function useSet<T>(initial?: Iterable<T>): UseSetResult<T> {\n const [set, setSet] = useState<Set<T>>(() => new Set(initial));\n\n const add = useCallback((value: T): void => {\n setSet((current) => {\n if (current.has(value)) return current;\n const next = new Set(current);\n next.add(value);\n return next;\n });\n }, []);\n\n const remove = useCallback((value: T): void => {\n setSet((current) => {\n if (!current.has(value)) return current;\n const next = new Set(current);\n next.delete(value);\n return next;\n });\n }, []);\n\n const clear = useCallback((): void => {\n setSet((current) => (current.size === 0 ? current : new Set<T>()));\n }, []);\n\n const has = useCallback((value: T): boolean => set.has(value), [set]);\n\n const toggle = useCallback((value: T): void => {\n setSet((current) => {\n const next = new Set(current);\n if (next.has(value)) next.delete(value);\n else next.add(value);\n return next;\n });\n }, []);\n\n return useMemo<UseSetResult<T>>(\n () => ({\n set,\n add,\n delete: remove,\n clear,\n has,\n toggle,\n size: set.size,\n }),\n [set, add, remove, clear, has, toggle],\n );\n}\n"],"mappings":"uBAoBA,SAAgB,EAAU,EAAwC,CAC9D,GAAM,CAAC,EAAK,IAAA,EAAU,EAAA,SAAA,KAAuB,IAAI,IAAI,CAAO,CAAC,EAEvD,GAAA,EAAM,EAAA,YAAA,CAAa,GAAmB,CACxC,EAAQ,GAAY,CAChB,GAAI,EAAQ,IAAI,CAAK,EAAG,OAAO,EAC/B,IAAM,EAAO,IAAI,IAAI,CAAO,EAE5B,OADA,EAAK,IAAI,CAAK,EACP,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEC,GAAA,EAAS,EAAA,YAAA,CAAa,GAAmB,CAC3C,EAAQ,GAAY,CAChB,GAAI,CAAC,EAAQ,IAAI,CAAK,EAAG,OAAO,EAChC,IAAM,EAAO,IAAI,IAAI,CAAO,EAE5B,OADA,EAAK,OAAO,CAAK,EACV,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEC,GAAA,EAAQ,EAAA,YAAA,KAAwB,CAClC,EAAQ,GAAa,EAAQ,OAAS,EAAI,EAAU,IAAI,GAAS,CACrE,EAAG,CAAC,CAAC,EAEC,GAAA,EAAM,EAAA,YAAA,CAAa,GAAsB,EAAI,IAAI,CAAK,EAAG,CAAC,CAAG,CAAC,EAE9D,GAAA,EAAS,EAAA,YAAA,CAAa,GAAmB,CAC3C,EAAQ,GAAY,CAChB,IAAM,EAAO,IAAI,IAAI,CAAO,EAG5B,OAFI,EAAK,IAAI,CAAK,EAAG,EAAK,OAAO,CAAK,EACjC,EAAK,IAAI,CAAK,EACZ,CACX,CAAC,CACL,EAAG,CAAC,CAAC,EAEL,OAAA,EAAO,EAAA,QAAA,MACI,CACH,MACA,MACA,OAAQ,EACR,QACA,MACA,SACA,KAAM,EAAI,IACd,GACA,CAAC,EAAK,EAAK,EAAQ,EAAO,EAAK,CAAM,CACzC,CACJ"}
@@ -1,2 +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;
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()}},[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
2
  //# sourceMappingURL=use-sortable.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-sortable.cjs","names":[],"sources":["../../src/hooks/use-sortable.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines, hook-lines — drag-and-drop with a keyboard path that\n * has to produce the same moves as the pointer path: pointer capture, auto-scroll\n * near the edges, the drop-index maths and the live-region announcements all read\n * one drag state. Two hooks would mean two copies of the index arithmetic, and the\n * two paths silently disagreeing is the bug this exists to prevent.\n */\nimport { 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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"}
1
+ {"version":3,"file":"use-sortable.cjs","names":[],"sources":["../../src/hooks/use-sortable.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines, hook-lines — drag-and-drop with a keyboard path that\n * has to produce the same moves as the pointer path: pointer capture, auto-scroll\n * near the edges, the drop-index maths and the live-region announcements all read\n * one drag state. Two hooks would mean two copies of the index arithmetic, and the\n * two paths silently disagreeing is the bug this exists to prevent.\n */\nimport { 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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"}
@@ -111,8 +111,6 @@ function o(i) {
111
111
  case "Escape":
112
112
  if (!r) return;
113
113
  n.preventDefault(), O();
114
- break;
115
- default: break;
116
114
  }
117
115
  }, [
118
116
  v,