tempest-react-sdk 0.38.3 → 0.39.1

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 (519) hide show
  1. package/README.md +1 -1
  2. package/dist/_virtual/_rolldown/runtime.cjs +1 -1
  3. package/dist/access/access-control-context.cjs.map +1 -1
  4. package/dist/access/use-can.cjs.map +1 -1
  5. package/dist/app/AppProviders.cjs.map +1 -1
  6. package/dist/app/AppProviders.js.map +1 -1
  7. package/dist/audio/use-audio-recorder.cjs.map +1 -1
  8. package/dist/audio/use-audio.cjs.map +1 -1
  9. package/dist/audio/use-microphone.cjs.map +1 -1
  10. package/dist/auth/create-auth-store.cjs.map +1 -1
  11. package/dist/auth/lazy-with-retry.cjs.map +1 -1
  12. package/dist/auth/use-passkey.cjs.map +1 -1
  13. package/dist/br/BrazilMap.cjs +1 -1
  14. package/dist/br/BrazilMap.cjs.map +1 -1
  15. package/dist/br/BrazilMap.js +2 -2
  16. package/dist/br/BrazilMap.js.map +1 -1
  17. package/dist/br/BrazilStateCitySelect.cjs.map +1 -1
  18. package/dist/br/BrazilStateCitySelect.js.map +1 -1
  19. package/dist/br/BrazilStateMap.cjs +1 -1
  20. package/dist/br/BrazilStateMap.cjs.map +1 -1
  21. package/dist/br/BrazilStateMap.js +2 -2
  22. package/dist/br/BrazilStateMap.js.map +1 -1
  23. package/dist/br/MapLegend.cjs.map +1 -1
  24. package/dist/br/MapLegend.js.map +1 -1
  25. package/dist/br/MapMarkers.cjs.map +1 -1
  26. package/dist/br/MapMarkers.js.map +1 -1
  27. package/dist/br/MunicipalitySearch.cjs.map +1 -1
  28. package/dist/br/MunicipalitySearch.js.map +1 -1
  29. package/dist/br/PixQRCode.cjs.map +1 -1
  30. package/dist/br/PixQRCode.js.map +1 -1
  31. package/dist/br/use-map-hover.cjs.map +1 -1
  32. package/dist/br/use-map-zoom.cjs.map +1 -1
  33. package/dist/capture/media-recorder.cjs +1 -1
  34. package/dist/capture/media-recorder.js +2 -2
  35. package/dist/capture/use-barcode-scanner.cjs +1 -1
  36. package/dist/capture/use-barcode-scanner.cjs.map +1 -1
  37. package/dist/capture/use-barcode-scanner.js +2 -2
  38. package/dist/capture/use-barcode-scanner.js.map +1 -1
  39. package/dist/capture/use-screen-capture.cjs.map +1 -1
  40. package/dist/capture/use-speech-recognition.cjs.map +1 -1
  41. package/dist/capture/use-torch.cjs.map +1 -1
  42. package/dist/capture/use-video-recorder.cjs.map +1 -1
  43. package/dist/charts/AreaChart.cjs.map +1 -1
  44. package/dist/charts/AreaChart.js.map +1 -1
  45. package/dist/charts/BarChart.cjs.map +1 -1
  46. package/dist/charts/BarChart.js.map +1 -1
  47. package/dist/charts/LineChart.cjs.map +1 -1
  48. package/dist/charts/LineChart.js.map +1 -1
  49. package/dist/charts/PieChart.cjs.map +1 -1
  50. package/dist/charts/PieChart.js.map +1 -1
  51. package/dist/charts/RadarChart.cjs.map +1 -1
  52. package/dist/charts/RadarChart.js.map +1 -1
  53. package/dist/charts/use-chart-colors.cjs.map +1 -1
  54. package/dist/components/AIChat/AIChat.cjs.map +1 -1
  55. package/dist/components/AIChat/AIChat.js.map +1 -1
  56. package/dist/components/AIChat/AIChatComposer.cjs.map +1 -1
  57. package/dist/components/AIChat/AIChatComposer.js.map +1 -1
  58. package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
  59. package/dist/components/AIChat/AIChatTurn.js.map +1 -1
  60. package/dist/components/Accordion/Accordion.cjs.map +1 -1
  61. package/dist/components/Accordion/Accordion.js.map +1 -1
  62. package/dist/components/Alert/Alert.cjs.map +1 -1
  63. package/dist/components/Alert/Alert.js.map +1 -1
  64. package/dist/components/AppBar/AppBar.cjs.map +1 -1
  65. package/dist/components/AppBar/AppBar.js.map +1 -1
  66. package/dist/components/AppShell/AppShell.cjs.map +1 -1
  67. package/dist/components/AppShell/AppShell.js.map +1 -1
  68. package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
  69. package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
  70. package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
  71. package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
  72. package/dist/components/Avatar/Avatar.cjs.map +1 -1
  73. package/dist/components/Avatar/Avatar.js.map +1 -1
  74. package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -1
  75. package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -1
  76. package/dist/components/Badge/Badge.cjs.map +1 -1
  77. package/dist/components/Badge/Badge.js.map +1 -1
  78. package/dist/components/Banner/Banner.cjs.map +1 -1
  79. package/dist/components/Banner/Banner.js.map +1 -1
  80. package/dist/components/BarcodeScanner/BarcodeScanner.cjs.map +1 -1
  81. package/dist/components/BarcodeScanner/BarcodeScanner.js.map +1 -1
  82. package/dist/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
  83. package/dist/components/BottomNavigation/BottomNavigation.js.map +1 -1
  84. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  85. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  86. package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
  87. package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  88. package/dist/components/Button/Button.cjs.map +1 -1
  89. package/dist/components/Button/Button.js.map +1 -1
  90. package/dist/components/Calendar/Calendar.cjs +1 -1
  91. package/dist/components/Calendar/Calendar.cjs.map +1 -1
  92. package/dist/components/Calendar/Calendar.js +38 -41
  93. package/dist/components/Calendar/Calendar.js.map +1 -1
  94. package/dist/components/Card/Card.cjs.map +1 -1
  95. package/dist/components/Card/Card.js.map +1 -1
  96. package/dist/components/Carousel/Carousel.cjs.map +1 -1
  97. package/dist/components/Carousel/Carousel.js.map +1 -1
  98. package/dist/components/Chat/Chat.cjs.map +1 -1
  99. package/dist/components/Chat/Chat.js.map +1 -1
  100. package/dist/components/Chat/ChatComposer.cjs.map +1 -1
  101. package/dist/components/Chat/ChatComposer.js.map +1 -1
  102. package/dist/components/Chat/chat-groups.cjs +1 -1
  103. package/dist/components/Chat/chat-groups.cjs.map +1 -1
  104. package/dist/components/Chat/chat-groups.js +2 -2
  105. package/dist/components/Chat/chat-groups.js.map +1 -1
  106. package/dist/components/Checkbox/Checkbox.cjs.map +1 -1
  107. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  108. package/dist/components/ChipInput/ChipInput.cjs.map +1 -1
  109. package/dist/components/ChipInput/ChipInput.js.map +1 -1
  110. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  111. package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -1
  112. package/dist/components/CodeBlock/CodeBlock.js.map +1 -1
  113. package/dist/components/Collapsible/Collapsible.cjs.map +1 -1
  114. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  115. package/dist/components/Combobox/Combobox.cjs.map +1 -1
  116. package/dist/components/Combobox/Combobox.js.map +1 -1
  117. package/dist/components/Command/Command.cjs.map +1 -1
  118. package/dist/components/Command/Command.js.map +1 -1
  119. package/dist/components/ConfirmDialog/ConfirmDialog.cjs.map +1 -1
  120. package/dist/components/ConfirmDialog/ConfirmDialog.js.map +1 -1
  121. package/dist/components/ContextMenu/ContextMenu.cjs.map +1 -1
  122. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  123. package/dist/components/CopyButton/CopyButton.cjs.map +1 -1
  124. package/dist/components/CopyButton/CopyButton.js.map +1 -1
  125. package/dist/components/DataList/DataList.cjs.map +1 -1
  126. package/dist/components/DataList/DataList.js.map +1 -1
  127. package/dist/components/DataTable/DataTable.cjs +1 -1
  128. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  129. package/dist/components/DataTable/DataTable.js +2 -2
  130. package/dist/components/DataTable/DataTable.js.map +1 -1
  131. package/dist/components/DataTable/EditableCell.cjs.map +1 -1
  132. package/dist/components/DataTable/EditableCell.js.map +1 -1
  133. package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
  134. package/dist/components/DateRangePicker/DateRangePicker.cjs.map +1 -1
  135. package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
  136. package/dist/components/DescriptionList/DescriptionList.cjs.map +1 -1
  137. package/dist/components/DescriptionList/DescriptionList.js.map +1 -1
  138. package/dist/components/Divider/Divider.cjs.map +1 -1
  139. package/dist/components/Divider/Divider.js.map +1 -1
  140. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  141. package/dist/components/Drawer/Drawer.js.map +1 -1
  142. package/dist/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
  143. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  144. package/dist/components/Dropzone/Dropzone.cjs.map +1 -1
  145. package/dist/components/Dropzone/Dropzone.js.map +1 -1
  146. package/dist/components/EmptyState/EmptyState.cjs.map +1 -1
  147. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  148. package/dist/components/ErrorState/ErrorState.cjs.map +1 -1
  149. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  150. package/dist/components/FileUpload/FileUpload.cjs +1 -1
  151. package/dist/components/FileUpload/FileUpload.cjs.map +1 -1
  152. package/dist/components/FileUpload/FileUpload.js +1 -1
  153. package/dist/components/FileUpload/FileUpload.js.map +1 -1
  154. package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
  155. package/dist/components/FilterBar/FilterBar.js.map +1 -1
  156. package/dist/components/FloatingActionButton/FloatingActionButton.cjs.map +1 -1
  157. package/dist/components/FloatingActionButton/FloatingActionButton.js.map +1 -1
  158. package/dist/components/Form/Form.cjs.map +1 -1
  159. package/dist/components/Form/Form.js.map +1 -1
  160. package/dist/components/HoverCard/HoverCard.cjs.map +1 -1
  161. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  162. package/dist/components/Image/Image.cjs.map +1 -1
  163. package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
  164. package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
  165. package/dist/components/ImageCropper/ImageCropper.js +1 -1
  166. package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
  167. package/dist/components/Input/Input.cjs.map +1 -1
  168. package/dist/components/Input/Input.js.map +1 -1
  169. package/dist/components/InstallBanner/InstallBanner.cjs.map +1 -1
  170. package/dist/components/InstallBanner/InstallBanner.js.map +1 -1
  171. package/dist/components/InstallButton/InstallButton.cjs.map +1 -1
  172. package/dist/components/InstallButton/InstallButton.js.map +1 -1
  173. package/dist/components/Kanban/Kanban.cjs.map +1 -1
  174. package/dist/components/Kanban/Kanban.js.map +1 -1
  175. package/dist/components/Label/Label.cjs.map +1 -1
  176. package/dist/components/Label/Label.js.map +1 -1
  177. package/dist/components/Lightbox/Lightbox.cjs.map +1 -1
  178. package/dist/components/Lightbox/Lightbox.js.map +1 -1
  179. package/dist/components/ListTile/ListTile.cjs.map +1 -1
  180. package/dist/components/ListTile/ListTile.js.map +1 -1
  181. package/dist/components/Markdown/Markdown.cjs +1 -1
  182. package/dist/components/Markdown/Markdown.cjs.map +1 -1
  183. package/dist/components/Markdown/Markdown.js +2 -2
  184. package/dist/components/Markdown/Markdown.js.map +1 -1
  185. package/dist/components/Masonry/Masonry.cjs.map +1 -1
  186. package/dist/components/Masonry/Masonry.js.map +1 -1
  187. package/dist/components/Menubar/Menubar.cjs.map +1 -1
  188. package/dist/components/Menubar/Menubar.js.map +1 -1
  189. package/dist/components/Modal/Modal.cjs.map +1 -1
  190. package/dist/components/Modal/Modal.js.map +1 -1
  191. package/dist/components/ModalsManager/ModalsManager.cjs.map +1 -1
  192. package/dist/components/ModalsManager/ModalsManager.js.map +1 -1
  193. package/dist/components/Money/Money.cjs.map +1 -1
  194. package/dist/components/Money/Money.js.map +1 -1
  195. package/dist/components/MultiSelect/MultiSelect.cjs.map +1 -1
  196. package/dist/components/MultiSelect/MultiSelect.js.map +1 -1
  197. package/dist/components/NProgress/NProgress.cjs.map +1 -1
  198. package/dist/components/Navbar/Navbar.cjs.map +1 -1
  199. package/dist/components/Navbar/Navbar.js.map +1 -1
  200. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  201. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  202. package/dist/components/NavigationRail/NavigationRail.cjs.map +1 -1
  203. package/dist/components/NavigationRail/NavigationRail.js.map +1 -1
  204. package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -1
  205. package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -1
  206. package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -1
  207. package/dist/components/OfflineIndicator/OfflineIndicator.cjs.map +1 -1
  208. package/dist/components/OfflineIndicator/OfflineIndicator.js.map +1 -1
  209. package/dist/components/Page/Page.cjs.map +1 -1
  210. package/dist/components/Page/Page.js.map +1 -1
  211. package/dist/components/Pagination/Pagination.cjs.map +1 -1
  212. package/dist/components/Pagination/Pagination.js.map +1 -1
  213. package/dist/components/PasswordInput/PasswordInput.cjs.map +1 -1
  214. package/dist/components/PasswordInput/PasswordInput.js.map +1 -1
  215. package/dist/components/PinInput/PinInput.cjs.map +1 -1
  216. package/dist/components/PinInput/PinInput.js.map +1 -1
  217. package/dist/components/Popover/Popover.cjs.map +1 -1
  218. package/dist/components/Popover/Popover.js.map +1 -1
  219. package/dist/components/Portal/Portal.cjs.map +1 -1
  220. package/dist/components/Progress/Progress.cjs.map +1 -1
  221. package/dist/components/Progress/Progress.js.map +1 -1
  222. package/dist/components/QRCode/QRCode.cjs.map +1 -1
  223. package/dist/components/QRCode/QRCode.js.map +1 -1
  224. package/dist/components/Radio/Radio.cjs.map +1 -1
  225. package/dist/components/Radio/Radio.js.map +1 -1
  226. package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
  227. package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
  228. package/dist/components/RatingStars/RatingStars.cjs.map +1 -1
  229. package/dist/components/RatingStars/RatingStars.js.map +1 -1
  230. package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
  231. package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
  232. package/dist/components/RelativeTime/RelativeTime.cjs.map +1 -1
  233. package/dist/components/RelativeTime/RelativeTime.js.map +1 -1
  234. package/dist/components/Resizable/Resizable.cjs.map +1 -1
  235. package/dist/components/Resizable/Resizable.js.map +1 -1
  236. package/dist/components/Scheduler/Scheduler.cjs.map +1 -1
  237. package/dist/components/Scheduler/Scheduler.js.map +1 -1
  238. package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
  239. package/dist/components/SearchBar/SearchBar.cjs.map +1 -1
  240. package/dist/components/SearchBar/SearchBar.js.map +1 -1
  241. package/dist/components/SegmentedControl/SegmentedControl.cjs.map +1 -1
  242. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  243. package/dist/components/Select/Select.cjs.map +1 -1
  244. package/dist/components/Select/Select.js.map +1 -1
  245. package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
  246. package/dist/components/Sidebar/Sidebar.js.map +1 -1
  247. package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -1
  248. package/dist/components/SignaturePad/SignaturePad.js.map +1 -1
  249. package/dist/components/Slider/Slider.cjs.map +1 -1
  250. package/dist/components/Slider/Slider.js.map +1 -1
  251. package/dist/components/Sparkline/Sparkline.cjs.map +1 -1
  252. package/dist/components/Sparkline/Sparkline.js.map +1 -1
  253. package/dist/components/Spinner/Spinner.cjs.map +1 -1
  254. package/dist/components/Spinner/Spinner.js.map +1 -1
  255. package/dist/components/Stat/Stat.cjs.map +1 -1
  256. package/dist/components/Stat/Stat.js.map +1 -1
  257. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  258. package/dist/components/Stepper/Stepper.js.map +1 -1
  259. package/dist/components/StepperInput/StepperInput.cjs.map +1 -1
  260. package/dist/components/StepperInput/StepperInput.js.map +1 -1
  261. package/dist/components/Switch/Switch.cjs.map +1 -1
  262. package/dist/components/Switch/Switch.js.map +1 -1
  263. package/dist/components/SyncStatusBadge/SyncStatusBadge.cjs.map +1 -1
  264. package/dist/components/SyncStatusBadge/SyncStatusBadge.js.map +1 -1
  265. package/dist/components/Table/Table.cjs.map +1 -1
  266. package/dist/components/Table/Table.js.map +1 -1
  267. package/dist/components/Tabs/Tabs.cjs.map +1 -1
  268. package/dist/components/Tabs/Tabs.js.map +1 -1
  269. package/dist/components/Tag/Tag.cjs.map +1 -1
  270. package/dist/components/Tag/Tag.js.map +1 -1
  271. package/dist/components/Textarea/Textarea.cjs.map +1 -1
  272. package/dist/components/Textarea/Textarea.js.map +1 -1
  273. package/dist/components/TimePicker/TimePicker.cjs.map +1 -1
  274. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  275. package/dist/components/Timeline/Timeline.cjs.map +1 -1
  276. package/dist/components/Timeline/Timeline.js.map +1 -1
  277. package/dist/components/Toast/ToastProvider.cjs.map +1 -1
  278. package/dist/components/Toast/ToastProvider.js.map +1 -1
  279. package/dist/components/Toggle/Toggle.cjs.map +1 -1
  280. package/dist/components/ToggleGroup/ToggleGroup.cjs.map +1 -1
  281. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  282. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  283. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  284. package/dist/components/Tour/Tour.cjs.map +1 -1
  285. package/dist/components/Tour/Tour.js.map +1 -1
  286. package/dist/components/Transfer/Transfer.cjs.map +1 -1
  287. package/dist/components/Transfer/Transfer.js.map +1 -1
  288. package/dist/components/TreeView/TreeView.cjs +1 -1
  289. package/dist/components/TreeView/TreeView.cjs.map +1 -1
  290. package/dist/components/TreeView/TreeView.js +1 -4
  291. package/dist/components/TreeView/TreeView.js.map +1 -1
  292. package/dist/components/UpdatePrompt/UpdatePrompt.cjs.map +1 -1
  293. package/dist/components/UpdatePrompt/UpdatePrompt.js.map +1 -1
  294. package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
  295. package/dist/components/VirtualList/VirtualList.js.map +1 -1
  296. package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
  297. package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
  298. package/dist/components/VisuallyHidden/VisuallyHidden.cjs.map +1 -1
  299. package/dist/components/Wizard/Wizard.cjs.map +1 -1
  300. package/dist/components/Wizard/Wizard.js.map +1 -1
  301. package/dist/data/data-provider-context.cjs.map +1 -1
  302. package/dist/data/use-resource.cjs.map +1 -1
  303. package/dist/editor/RichTextEditor.cjs.map +1 -1
  304. package/dist/editor/RichTextEditor.js.map +1 -1
  305. package/dist/error-boundary/use-error-handler.cjs.map +1 -1
  306. package/dist/feature-flags/FeatureFlagsProvider.cjs.map +1 -1
  307. package/dist/forms/FormField.cjs.map +1 -1
  308. package/dist/forms/masked-inputs.cjs.map +1 -1
  309. package/dist/forms/use-viacep.cjs.map +1 -1
  310. package/dist/forms/use-zod-form.cjs.map +1 -1
  311. package/dist/geo/TrajectoryMap.cjs.map +1 -1
  312. package/dist/geo/TrajectoryMap.js.map +1 -1
  313. package/dist/geo/leaflet-map.cjs.map +1 -1
  314. package/dist/geo/leaflet-map.js.map +1 -1
  315. package/dist/geo/use-position-tracker.cjs.map +1 -1
  316. package/dist/hooks/use-announce.cjs.map +1 -1
  317. package/dist/hooks/use-async.cjs.map +1 -1
  318. package/dist/hooks/use-before-install-prompt.cjs.map +1 -1
  319. package/dist/hooks/use-breakpoint.cjs.map +1 -1
  320. package/dist/hooks/use-click-outside.cjs.map +1 -1
  321. package/dist/hooks/use-client-filter.cjs.map +1 -1
  322. package/dist/hooks/use-clipboard.cjs.map +1 -1
  323. package/dist/hooks/use-counter.cjs.map +1 -1
  324. package/dist/hooks/use-debounce.cjs.map +1 -1
  325. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  326. package/dist/hooks/use-disclosure.cjs.map +1 -1
  327. package/dist/hooks/use-document-visibility.cjs.map +1 -1
  328. package/dist/hooks/use-event-listener.cjs.map +1 -1
  329. package/dist/hooks/use-geolocation.cjs.map +1 -1
  330. package/dist/hooks/use-hover.cjs.map +1 -1
  331. package/dist/hooks/use-idle.cjs.map +1 -1
  332. package/dist/hooks/use-install-prompt.cjs +1 -1
  333. package/dist/hooks/use-install-prompt.cjs.map +1 -1
  334. package/dist/hooks/use-install-prompt.js +1 -1
  335. package/dist/hooks/use-install-prompt.js.map +1 -1
  336. package/dist/hooks/use-intersection-observer.cjs.map +1 -1
  337. package/dist/hooks/use-interval.cjs.map +1 -1
  338. package/dist/hooks/use-is-first-render.cjs.map +1 -1
  339. package/dist/hooks/use-keyboard-shortcut.cjs +1 -1
  340. package/dist/hooks/use-keyboard-shortcut.cjs.map +1 -1
  341. package/dist/hooks/use-keyboard-shortcut.js +1 -1
  342. package/dist/hooks/use-keyboard-shortcut.js.map +1 -1
  343. package/dist/hooks/use-list-state.cjs.map +1 -1
  344. package/dist/hooks/use-local-storage.cjs.map +1 -1
  345. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  346. package/dist/hooks/use-long-press.cjs.map +1 -1
  347. package/dist/hooks/use-map.cjs.map +1 -1
  348. package/dist/hooks/use-media-devices.cjs.map +1 -1
  349. package/dist/hooks/use-media-permission.cjs.map +1 -1
  350. package/dist/hooks/use-media-query.cjs.map +1 -1
  351. package/dist/hooks/use-object-url.cjs.map +1 -1
  352. package/dist/hooks/use-online.cjs.map +1 -1
  353. package/dist/hooks/use-pagination.cjs.map +1 -1
  354. package/dist/hooks/use-previous.cjs.map +1 -1
  355. package/dist/hooks/use-queue.cjs.map +1 -1
  356. package/dist/hooks/use-resize-observer.cjs.map +1 -1
  357. package/dist/hooks/use-scroll-overflow.cjs.map +1 -1
  358. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  359. package/dist/hooks/use-set.cjs.map +1 -1
  360. package/dist/hooks/use-sortable.cjs +1 -1
  361. package/dist/hooks/use-sortable.cjs.map +1 -1
  362. package/dist/hooks/use-sortable.js +0 -2
  363. package/dist/hooks/use-sortable.js.map +1 -1
  364. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  365. package/dist/hooks/use-storage-estimate.cjs.map +1 -1
  366. package/dist/hooks/use-throttle.cjs.map +1 -1
  367. package/dist/hooks/use-timeout.cjs.map +1 -1
  368. package/dist/hooks/use-toggle.cjs.map +1 -1
  369. package/dist/hooks/use-window-size.cjs.map +1 -1
  370. package/dist/http/api-client.cjs +1 -1
  371. package/dist/http/api-client.cjs.map +1 -1
  372. package/dist/http/api-client.js +7 -5
  373. package/dist/http/api-client.js.map +1 -1
  374. package/dist/http/resumable-upload.cjs +1 -1
  375. package/dist/http/resumable-upload.cjs.map +1 -1
  376. package/dist/http/resumable-upload.js +1 -1
  377. package/dist/http/resumable-upload.js.map +1 -1
  378. package/dist/http/use-poll.cjs.map +1 -1
  379. package/dist/i18n/I18nProvider.cjs.map +1 -1
  380. package/dist/icons/Icon.cjs.map +1 -1
  381. package/dist/icons/IconProvider.cjs.map +1 -1
  382. package/dist/icons/icon-context.cjs.map +1 -1
  383. package/dist/icons/use-icon.cjs.map +1 -1
  384. package/dist/imaging/use-image-processing.cjs.map +1 -1
  385. package/dist/oauth/GoogleSignIn.cjs.map +1 -1
  386. package/dist/oauth/GoogleSignIn.js.map +1 -1
  387. package/dist/oauth/use-oauth-callback.cjs.map +1 -1
  388. package/dist/offline/use-offline-sync.cjs.map +1 -1
  389. package/dist/push/use-push-subscription.cjs.map +1 -1
  390. package/dist/query/QueryProvider.cjs.map +1 -1
  391. package/dist/query/constants.cjs +1 -1
  392. package/dist/query/constants.cjs.map +1 -1
  393. package/dist/query/constants.js +10 -10
  394. package/dist/query/constants.js.map +1 -1
  395. package/dist/query/create-query-keys.cjs +1 -1
  396. package/dist/query/create-query-keys.cjs.map +1 -1
  397. package/dist/query/create-query-keys.js +1 -1
  398. package/dist/query/create-query-keys.js.map +1 -1
  399. package/dist/query/offline-persistence.cjs.map +1 -1
  400. package/dist/query/use-cursor-query.cjs.map +1 -1
  401. package/dist/query/use-offline-mutation.cjs.map +1 -1
  402. package/dist/query/use-paginated-query.cjs.map +1 -1
  403. package/dist/router/AppRouter.cjs +1 -1
  404. package/dist/router/AppRouter.cjs.map +1 -1
  405. package/dist/router/AppRouter.js +7 -2
  406. package/dist/router/AppRouter.js.map +1 -1
  407. package/dist/sse/use-event-stream.cjs.map +1 -1
  408. package/dist/store/create-store.cjs.map +1 -1
  409. package/dist/tabular/use-tabular-predictor.cjs.map +1 -1
  410. package/dist/telemetry/TelemetryProvider.cjs.map +1 -1
  411. package/dist/theme/ThemeProvider.cjs.map +1 -1
  412. package/dist/theme/color.cjs +1 -1
  413. package/dist/theme/color.cjs.map +1 -1
  414. package/dist/theme/color.js +1 -1
  415. package/dist/theme/color.js.map +1 -1
  416. package/dist/utils/cn.cjs +1 -1
  417. package/dist/utils/cn.cjs.map +1 -1
  418. package/dist/utils/cn.js +1 -1
  419. package/dist/utils/cn.js.map +1 -1
  420. package/dist/utils/objects.cjs +1 -1
  421. package/dist/utils/objects.cjs.map +1 -1
  422. package/dist/utils/objects.js +1 -1
  423. package/dist/utils/objects.js.map +1 -1
  424. package/dist/utils/xlsx.cjs +1 -1
  425. package/dist/utils/xlsx.cjs.map +1 -1
  426. package/dist/utils/xlsx.js +3 -3
  427. package/dist/utils/xlsx.js.map +1 -1
  428. package/dist/vision/core/canvas.cjs +1 -1
  429. package/dist/vision/core/canvas.cjs.map +1 -1
  430. package/dist/vision/core/canvas.js +4 -4
  431. package/dist/vision/core/canvas.js.map +1 -1
  432. package/dist/vision/core/exceptions.cjs +1 -1
  433. package/dist/vision/core/exceptions.cjs.map +1 -1
  434. package/dist/vision/core/exceptions.js +2 -2
  435. package/dist/vision/core/exceptions.js.map +1 -1
  436. package/dist/vision/core/metadata.cjs +2 -2
  437. package/dist/vision/core/metadata.cjs.map +1 -1
  438. package/dist/vision/core/metadata.js +11 -8
  439. package/dist/vision/core/metadata.js.map +1 -1
  440. package/dist/vision/core/session.cjs +1 -1
  441. package/dist/vision/core/session.cjs.map +1 -1
  442. package/dist/vision/core/session.js +8 -5
  443. package/dist/vision/core/session.js.map +1 -1
  444. package/dist/vision/fusion.cjs +2 -0
  445. package/dist/vision/fusion.cjs.map +1 -0
  446. package/dist/vision/fusion.js +42 -0
  447. package/dist/vision/fusion.js.map +1 -0
  448. package/dist/vision/index.cjs +1 -1
  449. package/dist/vision/index.cjs.map +1 -1
  450. package/dist/vision/index.js +23 -20
  451. package/dist/vision/index.js.map +1 -1
  452. package/dist/vision/io/image.cjs +1 -1
  453. package/dist/vision/io/image.cjs.map +1 -1
  454. package/dist/vision/io/image.js +4 -2
  455. package/dist/vision/io/image.js.map +1 -1
  456. package/dist/vision/labels.cjs +1 -1
  457. package/dist/vision/labels.cjs.map +1 -1
  458. package/dist/vision/labels.js +7 -4
  459. package/dist/vision/labels.js.map +1 -1
  460. package/dist/vision/postprocess/detection.cjs +1 -1
  461. package/dist/vision/postprocess/detection.cjs.map +1 -1
  462. package/dist/vision/postprocess/detection.js +3 -10
  463. package/dist/vision/postprocess/detection.js.map +1 -1
  464. package/dist/vision/postprocess/segmentation.cjs +1 -1
  465. package/dist/vision/postprocess/segmentation.cjs.map +1 -1
  466. package/dist/vision/postprocess/segmentation.js +11 -15
  467. package/dist/vision/postprocess/segmentation.js.map +1 -1
  468. package/dist/vision/preprocess/image.cjs +1 -1
  469. package/dist/vision/preprocess/image.cjs.map +1 -1
  470. package/dist/vision/preprocess/image.js +4 -2
  471. package/dist/vision/preprocess/image.js.map +1 -1
  472. package/dist/vision/preprocess/pipeline.cjs +2 -0
  473. package/dist/vision/preprocess/pipeline.cjs.map +1 -0
  474. package/dist/vision/preprocess/pipeline.js +61 -0
  475. package/dist/vision/preprocess/pipeline.js.map +1 -0
  476. package/dist/vision/results.cjs +1 -1
  477. package/dist/vision/results.cjs.map +1 -1
  478. package/dist/vision/results.js +23 -2
  479. package/dist/vision/results.js.map +1 -1
  480. package/dist/vision/tasks/base.cjs +1 -1
  481. package/dist/vision/tasks/base.cjs.map +1 -1
  482. package/dist/vision/tasks/base.js +11 -2
  483. package/dist/vision/tasks/base.js.map +1 -1
  484. package/dist/vision/tasks/classifier.cjs +1 -1
  485. package/dist/vision/tasks/classifier.cjs.map +1 -1
  486. package/dist/vision/tasks/classifier.js +2 -2
  487. package/dist/vision/tasks/classifier.js.map +1 -1
  488. package/dist/vision/tasks/detectClassify.cjs +2 -0
  489. package/dist/vision/tasks/detectClassify.cjs.map +1 -0
  490. package/dist/vision/tasks/detectClassify.js +222 -0
  491. package/dist/vision/tasks/detectClassify.js.map +1 -0
  492. package/dist/vision/tasks/detector.cjs +1 -1
  493. package/dist/vision/tasks/detector.cjs.map +1 -1
  494. package/dist/vision/tasks/detector.js +54 -29
  495. package/dist/vision/tasks/detector.js.map +1 -1
  496. package/dist/vision/tasks/segmenter.cjs +1 -1
  497. package/dist/vision/tasks/segmenter.cjs.map +1 -1
  498. package/dist/vision/tasks/segmenter.js +53 -28
  499. package/dist/vision/tasks/segmenter.js.map +1 -1
  500. package/dist/vision/types.cjs.map +1 -1
  501. package/dist/vision/types.js.map +1 -1
  502. package/dist/vision/use-camera-stream.cjs.map +1 -1
  503. package/dist/vision/use-live-luminance.cjs.map +1 -1
  504. package/dist/vision.cjs +1 -1
  505. package/dist/vision.d.ts +1517 -962
  506. package/dist/vision.js +25 -22
  507. package/dist/vite/create-vite-config.cjs +1 -1
  508. package/dist/vite/create-vite-config.cjs.map +1 -1
  509. package/dist/vite/create-vite-config.js +3 -3
  510. package/dist/vite/create-vite-config.js.map +1 -1
  511. package/dist/vite/tempest-icons.cjs.map +1 -1
  512. package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
  513. package/dist/vite/tempest-pwa-icons.cjs.map +1 -1
  514. package/dist/ws/use-web-socket.cjs +1 -1
  515. package/dist/ws/use-web-socket.cjs.map +1 -1
  516. package/dist/ws/use-web-socket.js +5 -3
  517. package/dist/ws/use-web-socket.js.map +1 -1
  518. package/package.json +2 -2
  519. package/template/package.json +1 -1
@@ -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,
@@ -1 +1 @@
1
- {"version":3,"file":"use-sortable.js","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.js","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 +1 @@
1
- {"version":3,"file":"use-stable-callback.cjs","names":[],"sources":["../../src/hooks/use-stable-callback.ts"],"sourcesContent":["/* eslint-disable react-hooks/refs -- writing at render time is deliberate; an effect would add a staleness window (see the docstring) */\nimport { useCallback, useRef } from \"react\";\n\n/**\n * Returns a stable function reference that always invokes the latest\n * `callback` argument. Use to break dependency cycles in effects without\n * triggering re-runs when the callback identity changes.\n *\n * The assignment happens **during render** on purpose. Moving it into an effect\n * would satisfy the React Compiler rules but open a one-commit staleness window:\n * an effect declared before this hook's own effect, in the same commit, would call\n * the previous render's callback. This is a primitive other hooks build on, so a\n * subtle staleness here is worse than the rule violation. Prefer React's\n * `useEffectEvent` once it ships as stable.\n */\nexport function useStableCallback<TArgs extends unknown[], TReturn>(\n callback: (...args: TArgs) => TReturn,\n): (...args: TArgs) => TReturn {\n const ref = useRef(callback);\n ref.current = callback;\n return useCallback((...args: TArgs) => ref.current(...args), []);\n}\n"],"mappings":"uBAeA,SAAgB,EACZ,EAC2B,CAC3B,IAAM,GAAA,EAAA,EAAA,OAAA,CAAa,CAAQ,EAE3B,MADA,GAAI,QAAU,GACd,EAAA,EAAA,YAAA,EAAoB,GAAG,IAAgB,EAAI,QAAQ,GAAG,CAAI,EAAG,CAAC,CAAC,CACnE"}
1
+ {"version":3,"file":"use-stable-callback.cjs","names":[],"sources":["../../src/hooks/use-stable-callback.ts"],"sourcesContent":["/* eslint-disable react-hooks/refs -- writing at render time is deliberate; an effect would add a staleness window (see the docstring) */\nimport { useCallback, useRef } from \"react\";\n\n/**\n * Returns a stable function reference that always invokes the latest\n * `callback` argument. Use to break dependency cycles in effects without\n * triggering re-runs when the callback identity changes.\n *\n * The assignment happens **during render** on purpose. Moving it into an effect\n * would satisfy the React Compiler rules but open a one-commit staleness window:\n * an effect declared before this hook's own effect, in the same commit, would call\n * the previous render's callback. This is a primitive other hooks build on, so a\n * subtle staleness here is worse than the rule violation. Prefer React's\n * `useEffectEvent` once it ships as stable.\n */\nexport function useStableCallback<TArgs extends unknown[], TReturn>(\n callback: (...args: TArgs) => TReturn,\n): (...args: TArgs) => TReturn {\n const ref = useRef(callback);\n ref.current = callback;\n return useCallback((...args: TArgs) => ref.current(...args), []);\n}\n"],"mappings":"uBAeA,SAAgB,EACZ,EAC2B,CAC3B,IAAM,GAAA,EAAM,EAAA,OAAA,CAAO,CAAQ,EAE3B,MADA,GAAI,QAAU,GACd,EAAO,EAAA,YAAA,EAAa,GAAG,IAAgB,EAAI,QAAQ,GAAG,CAAI,EAAG,CAAC,CAAC,CACnE"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-storage-estimate.cjs","names":[],"sources":["../../src/hooks/use-storage-estimate.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/** Raw usage/quota reading from the Storage API, in bytes. */\nexport interface StorageEstimate {\n /** Bytes currently used by this origin, or `null` when unknown. */\n usage: number | null;\n /** Total bytes available to this origin, or `null` when unknown. */\n quota: number | null;\n}\n\n/**\n * `true` when `navigator.storage` exposes the estimate/persist APIs. Guards\n * every call so the helpers stay safe under SSR and older browsers.\n */\nfunction storageManagerAvailable(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n \"storage\" in navigator &&\n typeof navigator.storage?.estimate === \"function\"\n );\n}\n\n/**\n * Read the origin's current storage usage and quota.\n *\n * @returns The estimate, or `{ usage: null, quota: null }` when unsupported.\n */\nexport async function estimateStorage(): Promise<StorageEstimate> {\n if (!storageManagerAvailable()) return { usage: null, quota: null };\n const estimate = await navigator.storage.estimate();\n return { usage: estimate.usage ?? null, quota: estimate.quota ?? null };\n}\n\n/**\n * Ask the browser to make this origin's storage persistent, so IndexedDB and\n * the Cache Storage are not silently evicted under disk pressure — essential\n * for durable offline-first data.\n *\n * The browser may grant silently, prompt, or deny based on engagement heuristics.\n *\n * @returns `true` when storage is (now or already) persisted, else `false`.\n */\nexport async function requestPersistentStorage(): Promise<boolean> {\n if (\n typeof navigator === \"undefined\" ||\n !(\"storage\" in navigator) ||\n typeof navigator.storage?.persist !== \"function\"\n ) {\n return false;\n }\n if (typeof navigator.storage.persisted === \"function\") {\n const already = await navigator.storage.persisted();\n if (already) return true;\n }\n return navigator.storage.persist();\n}\n\n/** Reactive storage-quota state exposed by {@link useStorageEstimate}. */\nexport interface UseStorageEstimateResult extends StorageEstimate {\n /** `true` when the Storage API is available. */\n supported: boolean;\n /** `usage / quota` in `[0, 1]`, or `null` when either value is unknown. */\n ratio: number | null;\n /** Whether storage is persisted, `null` before the first read / unsupported. */\n persisted: boolean | null;\n /** `true` during the initial read or a `refresh`. */\n loading: boolean;\n /** Re-read usage/quota and the persisted flag from the browser. */\n refresh: () => Promise<void>;\n /** Request persistent storage; refreshes state and returns the outcome. */\n requestPersist: () => Promise<boolean>;\n}\n\n/**\n * Track the origin's storage usage, quota and persistence flag, refreshing on\n * demand. Pair with {@link requestPersistentStorage} to surface a \"usando X de\n * Y MB\" meter and a \"tornar armazenamento permanente\" action.\n *\n * @param options - `pollMs` re-reads the estimate on an interval (`0` = off,\n * the default).\n * @returns The reactive storage state and actions.\n *\n * @example\n * const { usage, quota, ratio, persisted, requestPersist } = useStorageEstimate();\n * return <Meter value={ratio ?? 0} onClick={requestPersist} />;\n */\nexport function useStorageEstimate(options: { pollMs?: number } = {}): UseStorageEstimateResult {\n const { pollMs = 0 } = options;\n const [supported] = useState<boolean>(() => storageManagerAvailable());\n const [usage, setUsage] = useState<number | null>(null);\n const [quota, setQuota] = useState<number | null>(null);\n const [persisted, setPersisted] = useState<boolean | null>(null);\n const [loading, setLoading] = useState<boolean>(supported);\n\n const refresh = useCallback(async () => {\n if (!supported) return;\n setLoading(true);\n try {\n const estimate = await estimateStorage();\n setUsage(estimate.usage);\n setQuota(estimate.quota);\n if (typeof navigator.storage?.persisted === \"function\") {\n setPersisted(await navigator.storage.persisted());\n }\n } finally {\n setLoading(false);\n }\n }, [supported]);\n\n const requestPersist = useCallback(async () => {\n const granted = await requestPersistentStorage();\n await refresh();\n setPersisted(granted);\n return granted;\n }, [refresh]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n useEffect(() => {\n if (pollMs <= 0 || !supported || typeof window === \"undefined\") return;\n const id = window.setInterval(() => {\n void refresh();\n }, pollMs);\n return () => window.clearInterval(id);\n }, [pollMs, supported, refresh]);\n\n const ratio = usage !== null && quota !== null && quota > 0 ? usage / quota : null;\n\n return {\n supported,\n usage,\n quota,\n ratio,\n persisted,\n loading,\n refresh,\n requestPersist,\n };\n}\n"],"mappings":"uBAcA,SAAS,GAAmC,CACxC,OACI,OAAO,UAAc,KACrB,YAAa,WACb,OAAO,UAAU,SAAS,UAAa,UAE/C,CAOA,eAAsB,GAA4C,CAC9D,GAAI,CAAC,EAAwB,EAAG,MAAO,CAAE,MAAO,KAAM,MAAO,IAAK,EAClE,IAAM,EAAW,MAAM,UAAU,QAAQ,SAAS,EAClD,MAAO,CAAE,MAAO,EAAS,OAAS,KAAM,MAAO,EAAS,OAAS,IAAK,CAC1E,CAWA,eAAsB,GAA6C,CAY/D,OAVI,OAAO,UAAc,KACrB,EAAE,YAAa,YACf,OAAO,UAAU,SAAS,SAAY,WAE/B,GAEP,OAAO,UAAU,QAAQ,WAAc,YAEnC,MADkB,UAAU,QAAQ,UAAU,EAC9B,GAEjB,UAAU,QAAQ,QAAQ,CACrC,CA+BA,SAAgB,EAAmB,EAA+B,CAAC,EAA6B,CAC5F,GAAM,CAAE,SAAS,GAAM,EACjB,CAAC,IAAA,EAAA,EAAA,SAAA,KAAqC,EAAwB,CAAC,EAC/D,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAAoC,IAAI,EAChD,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAAoC,IAAI,EAChD,CAAC,EAAW,IAAA,EAAA,EAAA,SAAA,CAAyC,IAAI,EACzD,CAAC,EAAS,IAAA,EAAA,EAAA,SAAA,CAAgC,CAAS,EAEnD,GAAA,EAAA,EAAA,YAAA,CAAsB,SAAY,CAC/B,KACL,GAAW,EAAI,EACf,GAAI,CACA,IAAM,EAAW,MAAM,EAAgB,EACvC,EAAS,EAAS,KAAK,EACvB,EAAS,EAAS,KAAK,EACnB,OAAO,UAAU,SAAS,WAAc,YACxC,EAAa,MAAM,UAAU,QAAQ,UAAU,CAAC,CAExD,QAAU,CACN,EAAW,EAAK,CACpB,CAVe,CAWnB,EAAG,CAAC,CAAS,CAAC,EAER,GAAA,EAAA,EAAA,YAAA,CAA6B,SAAY,CAC3C,IAAM,EAAU,MAAM,EAAyB,EAG/C,OAFA,MAAM,EAAQ,EACd,EAAa,CAAO,EACb,CACX,EAAG,CAAC,CAAO,CAAC,EAgBZ,OAdA,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAa,CACjB,EAAG,CAAC,CAAO,CAAC,GAEZ,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,GAAU,GAAK,CAAC,GAAa,OAAO,OAAW,IAAa,OAChE,IAAM,EAAK,OAAO,gBAAkB,CAChC,EAAa,CACjB,EAAG,CAAM,EACT,UAAa,OAAO,cAAc,CAAE,CACxC,EAAG,CAAC,EAAQ,EAAW,CAAO,CAAC,EAIxB,CACH,YACA,QACA,QACA,MANU,IAAU,MAAQ,IAAU,MAAQ,EAAQ,EAAI,EAAQ,EAAQ,KAO1E,YACA,UACA,UACA,gBACJ,CACJ"}
1
+ {"version":3,"file":"use-storage-estimate.cjs","names":[],"sources":["../../src/hooks/use-storage-estimate.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/** Raw usage/quota reading from the Storage API, in bytes. */\nexport interface StorageEstimate {\n /** Bytes currently used by this origin, or `null` when unknown. */\n usage: number | null;\n /** Total bytes available to this origin, or `null` when unknown. */\n quota: number | null;\n}\n\n/**\n * `true` when `navigator.storage` exposes the estimate/persist APIs. Guards\n * every call so the helpers stay safe under SSR and older browsers.\n */\nfunction storageManagerAvailable(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n \"storage\" in navigator &&\n typeof navigator.storage?.estimate === \"function\"\n );\n}\n\n/**\n * Read the origin's current storage usage and quota.\n *\n * @returns The estimate, or `{ usage: null, quota: null }` when unsupported.\n */\nexport async function estimateStorage(): Promise<StorageEstimate> {\n if (!storageManagerAvailable()) return { usage: null, quota: null };\n const estimate = await navigator.storage.estimate();\n return { usage: estimate.usage ?? null, quota: estimate.quota ?? null };\n}\n\n/**\n * Ask the browser to make this origin's storage persistent, so IndexedDB and\n * the Cache Storage are not silently evicted under disk pressure — essential\n * for durable offline-first data.\n *\n * The browser may grant silently, prompt, or deny based on engagement heuristics.\n *\n * @returns `true` when storage is (now or already) persisted, else `false`.\n */\nexport async function requestPersistentStorage(): Promise<boolean> {\n if (\n typeof navigator === \"undefined\" ||\n !(\"storage\" in navigator) ||\n typeof navigator.storage?.persist !== \"function\"\n ) {\n return false;\n }\n if (typeof navigator.storage.persisted === \"function\") {\n const already = await navigator.storage.persisted();\n if (already) return true;\n }\n return navigator.storage.persist();\n}\n\n/** Reactive storage-quota state exposed by {@link useStorageEstimate}. */\nexport interface UseStorageEstimateResult extends StorageEstimate {\n /** `true` when the Storage API is available. */\n supported: boolean;\n /** `usage / quota` in `[0, 1]`, or `null` when either value is unknown. */\n ratio: number | null;\n /** Whether storage is persisted, `null` before the first read / unsupported. */\n persisted: boolean | null;\n /** `true` during the initial read or a `refresh`. */\n loading: boolean;\n /** Re-read usage/quota and the persisted flag from the browser. */\n refresh: () => Promise<void>;\n /** Request persistent storage; refreshes state and returns the outcome. */\n requestPersist: () => Promise<boolean>;\n}\n\n/**\n * Track the origin's storage usage, quota and persistence flag, refreshing on\n * demand. Pair with {@link requestPersistentStorage} to surface a \"usando X de\n * Y MB\" meter and a \"tornar armazenamento permanente\" action.\n *\n * @param options - `pollMs` re-reads the estimate on an interval (`0` = off,\n * the default).\n * @returns The reactive storage state and actions.\n *\n * @example\n * const { usage, quota, ratio, persisted, requestPersist } = useStorageEstimate();\n * return <Meter value={ratio ?? 0} onClick={requestPersist} />;\n */\nexport function useStorageEstimate(options: { pollMs?: number } = {}): UseStorageEstimateResult {\n const { pollMs = 0 } = options;\n const [supported] = useState<boolean>(() => storageManagerAvailable());\n const [usage, setUsage] = useState<number | null>(null);\n const [quota, setQuota] = useState<number | null>(null);\n const [persisted, setPersisted] = useState<boolean | null>(null);\n const [loading, setLoading] = useState<boolean>(supported);\n\n const refresh = useCallback(async () => {\n if (!supported) return;\n setLoading(true);\n try {\n const estimate = await estimateStorage();\n setUsage(estimate.usage);\n setQuota(estimate.quota);\n if (typeof navigator.storage?.persisted === \"function\") {\n setPersisted(await navigator.storage.persisted());\n }\n } finally {\n setLoading(false);\n }\n }, [supported]);\n\n const requestPersist = useCallback(async () => {\n const granted = await requestPersistentStorage();\n await refresh();\n setPersisted(granted);\n return granted;\n }, [refresh]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n useEffect(() => {\n if (pollMs <= 0 || !supported || typeof window === \"undefined\") return;\n const id = window.setInterval(() => {\n void refresh();\n }, pollMs);\n return () => window.clearInterval(id);\n }, [pollMs, supported, refresh]);\n\n const ratio = usage !== null && quota !== null && quota > 0 ? usage / quota : null;\n\n return {\n supported,\n usage,\n quota,\n ratio,\n persisted,\n loading,\n refresh,\n requestPersist,\n };\n}\n"],"mappings":"uBAcA,SAAS,GAAmC,CACxC,OACI,OAAO,UAAc,KACrB,YAAa,WACb,OAAO,UAAU,SAAS,UAAa,UAE/C,CAOA,eAAsB,GAA4C,CAC9D,GAAI,CAAC,EAAwB,EAAG,MAAO,CAAE,MAAO,KAAM,MAAO,IAAK,EAClE,IAAM,EAAW,MAAM,UAAU,QAAQ,SAAS,EAClD,MAAO,CAAE,MAAO,EAAS,OAAS,KAAM,MAAO,EAAS,OAAS,IAAK,CAC1E,CAWA,eAAsB,GAA6C,CAY/D,OAVI,OAAO,UAAc,KACrB,EAAE,YAAa,YACf,OAAO,UAAU,SAAS,SAAY,WAE/B,GAEP,OAAO,UAAU,QAAQ,WAAc,YAEnC,MADkB,UAAU,QAAQ,UAAU,EAC9B,GAEjB,UAAU,QAAQ,QAAQ,CACrC,CA+BA,SAAgB,EAAmB,EAA+B,CAAC,EAA6B,CAC5F,GAAM,CAAE,SAAS,GAAM,EACjB,CAAC,IAAA,EAAa,EAAA,SAAA,KAAwB,EAAwB,CAAC,EAC/D,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAwB,IAAI,EAChD,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAwB,IAAI,EAChD,CAAC,EAAW,IAAA,EAAgB,EAAA,SAAA,CAAyB,IAAI,EACzD,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAAkB,CAAS,EAEnD,GAAA,EAAU,EAAA,YAAA,CAAY,SAAY,CAC/B,KACL,GAAW,EAAI,EACf,GAAI,CACA,IAAM,EAAW,MAAM,EAAgB,EACvC,EAAS,EAAS,KAAK,EACvB,EAAS,EAAS,KAAK,EACnB,OAAO,UAAU,SAAS,WAAc,YACxC,EAAa,MAAM,UAAU,QAAQ,UAAU,CAAC,CAExD,QAAU,CACN,EAAW,EAAK,CACpB,CAVe,CAWnB,EAAG,CAAC,CAAS,CAAC,EAER,GAAA,EAAiB,EAAA,YAAA,CAAY,SAAY,CAC3C,IAAM,EAAU,MAAM,EAAyB,EAG/C,OAFA,MAAM,EAAQ,EACd,EAAa,CAAO,EACb,CACX,EAAG,CAAC,CAAO,CAAC,EAgBZ,OAdA,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAa,CACjB,EAAG,CAAC,CAAO,CAAC,GAEZ,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,GAAU,GAAK,CAAC,GAAa,OAAO,OAAW,IAAa,OAChE,IAAM,EAAK,OAAO,gBAAkB,CAChC,EAAa,CACjB,EAAG,CAAM,EACT,UAAa,OAAO,cAAc,CAAE,CACxC,EAAG,CAAC,EAAQ,EAAW,CAAO,CAAC,EAIxB,CACH,YACA,QACA,QACA,MANU,IAAU,MAAQ,IAAU,MAAQ,EAAQ,EAAI,EAAQ,EAAQ,KAO1E,YACA,UACA,UACA,gBACJ,CACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-throttle.cjs","names":[],"sources":["../../src/hooks/use-throttle.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\n\n/**\n * Return a value that updates at most once every `delay` ms. Complements\n * `useDebounce` — throttle emits on the leading edge and again after the\n * interval; debounce only emits after a period of stillness.\n *\n * @example\n * const throttledScroll = useThrottle(scrollY, 100);\n */\nexport function useThrottle<T>(value: T, delay: number): T {\n const [throttled, setThrottled] = useState<T>(value);\n const lastEmitRef = useRef<number>(0);\n const pendingRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n const now = Date.now();\n const elapsed = now - lastEmitRef.current;\n if (elapsed >= delay) {\n lastEmitRef.current = now;\n setThrottled(value);\n } else {\n if (pendingRef.current) clearTimeout(pendingRef.current);\n pendingRef.current = setTimeout(() => {\n lastEmitRef.current = Date.now();\n setThrottled(value);\n }, delay - elapsed);\n }\n return () => {\n if (pendingRef.current) clearTimeout(pendingRef.current);\n };\n }, [value, delay]);\n\n return throttled;\n}\n"],"mappings":"uBAUA,SAAgB,EAAe,EAAU,EAAkB,CACvD,GAAM,CAAC,EAAW,IAAA,EAAA,EAAA,SAAA,CAA4B,CAAK,EAC7C,GAAA,EAAA,EAAA,OAAA,CAA6B,CAAC,EAC9B,GAAA,EAAA,EAAA,OAAA,CAA0D,IAAI,EAoBpE,OAlBA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAM,EAAM,KAAK,IAAI,EACf,EAAU,EAAM,EAAY,QAWlC,OAVI,GAAW,GACX,EAAY,QAAU,EACtB,EAAa,CAAK,IAEd,EAAW,SAAS,aAAa,EAAW,OAAO,EACvD,EAAW,QAAU,eAAiB,CAClC,EAAY,QAAU,KAAK,IAAI,EAC/B,EAAa,CAAK,CACtB,EAAG,EAAQ,CAAO,OAET,CACL,EAAW,SAAS,aAAa,EAAW,OAAO,CAC3D,CACJ,EAAG,CAAC,EAAO,CAAK,CAAC,EAEV,CACX"}
1
+ {"version":3,"file":"use-throttle.cjs","names":[],"sources":["../../src/hooks/use-throttle.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\n\n/**\n * Return a value that updates at most once every `delay` ms. Complements\n * `useDebounce` — throttle emits on the leading edge and again after the\n * interval; debounce only emits after a period of stillness.\n *\n * @example\n * const throttledScroll = useThrottle(scrollY, 100);\n */\nexport function useThrottle<T>(value: T, delay: number): T {\n const [throttled, setThrottled] = useState<T>(value);\n const lastEmitRef = useRef<number>(0);\n const pendingRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n const now = Date.now();\n const elapsed = now - lastEmitRef.current;\n if (elapsed >= delay) {\n lastEmitRef.current = now;\n setThrottled(value);\n } else {\n if (pendingRef.current) clearTimeout(pendingRef.current);\n pendingRef.current = setTimeout(() => {\n lastEmitRef.current = Date.now();\n setThrottled(value);\n }, delay - elapsed);\n }\n return () => {\n if (pendingRef.current) clearTimeout(pendingRef.current);\n };\n }, [value, delay]);\n\n return throttled;\n}\n"],"mappings":"uBAUA,SAAgB,EAAe,EAAU,EAAkB,CACvD,GAAM,CAAC,EAAW,IAAA,EAAgB,EAAA,SAAA,CAAY,CAAK,EAC7C,GAAA,EAAc,EAAA,OAAA,CAAe,CAAC,EAC9B,GAAA,EAAa,EAAA,OAAA,CAA6C,IAAI,EAoBpE,OAlBA,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAM,EAAM,KAAK,IAAI,EACf,EAAU,EAAM,EAAY,QAWlC,OAVI,GAAW,GACX,EAAY,QAAU,EACtB,EAAa,CAAK,IAEd,EAAW,SAAS,aAAa,EAAW,OAAO,EACvD,EAAW,QAAU,eAAiB,CAClC,EAAY,QAAU,KAAK,IAAI,EAC/B,EAAa,CAAK,CACtB,EAAG,EAAQ,CAAO,OAET,CACL,EAAW,SAAS,aAAa,EAAW,OAAO,CAC3D,CACJ,EAAG,CAAC,EAAO,CAAK,CAAC,EAEV,CACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-timeout.cjs","names":[],"sources":["../../src/hooks/use-timeout.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\n\n/**\n * Run a callback after `delay` ms. Pass `null` to disable. Resets when\n * `delay` changes; the callback ref always points at the latest closure.\n *\n * @example\n * useTimeout(() => setShow(false), show ? 3000 : null);\n */\nexport function useTimeout(fn: () => void, delay: number | null): void {\n const fnRef = useRef(fn);\n useEffect(() => {\n fnRef.current = fn;\n }, [fn]);\n\n useEffect(() => {\n if (delay === null) return;\n const id = setTimeout(() => fnRef.current(), delay);\n return () => clearTimeout(id);\n }, [delay]);\n}\n"],"mappings":"uBASA,SAAgB,EAAW,EAAgB,EAA4B,CACnE,IAAM,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,GAAI,IAAU,KAAM,OACpB,IAAM,EAAK,eAAiB,EAAM,QAAQ,EAAG,CAAK,EAClD,UAAa,aAAa,CAAE,CAChC,EAAG,CAAC,CAAK,CAAC,CACd"}
1
+ {"version":3,"file":"use-timeout.cjs","names":[],"sources":["../../src/hooks/use-timeout.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\n\n/**\n * Run a callback after `delay` ms. Pass `null` to disable. Resets when\n * `delay` changes; the callback ref always points at the latest closure.\n *\n * @example\n * useTimeout(() => setShow(false), show ? 3000 : null);\n */\nexport function useTimeout(fn: () => void, delay: number | null): void {\n const fnRef = useRef(fn);\n useEffect(() => {\n fnRef.current = fn;\n }, [fn]);\n\n useEffect(() => {\n if (delay === null) return;\n const id = setTimeout(() => fnRef.current(), delay);\n return () => clearTimeout(id);\n }, [delay]);\n}\n"],"mappings":"uBASA,SAAgB,EAAW,EAAgB,EAA4B,CACnE,IAAM,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,GAAI,IAAU,KAAM,OACpB,IAAM,EAAK,eAAiB,EAAM,QAAQ,EAAG,CAAK,EAClD,UAAa,aAAa,CAAE,CAChC,EAAG,CAAC,CAAK,CAAC,CACd"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-toggle.cjs","names":[],"sources":["../../src/hooks/use-toggle.ts"],"sourcesContent":["import { useCallback, useState } from \"react\";\n\nexport interface ToggleHelpers {\n toggle: () => void;\n setTrue: () => void;\n setFalse: () => void;\n set: (next: boolean) => void;\n}\n\n/**\n * Boolean state with `toggle`/`setTrue`/`setFalse` helpers.\n *\n * @param initial - initial value (default `false`).\n * @returns Tuple `[value, helpers]`.\n */\nexport function useToggle(initial = false): [boolean, ToggleHelpers] {\n const [value, setValue] = useState<boolean>(initial);\n\n const toggle = useCallback((): void => setValue((current) => !current), []);\n const setTrue = useCallback((): void => setValue(true), []);\n const setFalse = useCallback((): void => setValue(false), []);\n const set = useCallback((next: boolean): void => setValue(next), []);\n\n return [value, { toggle, setTrue, setFalse, set }];\n}\n"],"mappings":"uBAeA,SAAgB,EAAU,EAAU,GAAiC,CACjE,GAAM,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,CAA8B,CAAO,EAOnD,MAAO,CAAC,EAAO,CAAE,QAAA,EAAA,EAAA,YAAA,KALsB,EAAU,GAAY,CAAC,CAAO,EAAG,CAAC,CAKxD,EAAQ,SAAA,EAAA,EAAA,YAAA,KAJe,EAAS,EAAI,EAAG,CAAC,CAIhC,EAAS,UAAA,EAAA,EAAA,YAAA,KAHO,EAAS,EAAK,EAAG,CAAC,CAGzB,EAAU,KAAA,EAAA,EAAA,YAAA,CAFnB,GAAwB,EAAS,CAAI,EAAG,CAAC,CAEtB,CAAI,CAAC,CACrD"}
1
+ {"version":3,"file":"use-toggle.cjs","names":[],"sources":["../../src/hooks/use-toggle.ts"],"sourcesContent":["import { useCallback, useState } from \"react\";\n\nexport interface ToggleHelpers {\n toggle: () => void;\n setTrue: () => void;\n setFalse: () => void;\n set: (next: boolean) => void;\n}\n\n/**\n * Boolean state with `toggle`/`setTrue`/`setFalse` helpers.\n *\n * @param initial - initial value (default `false`).\n * @returns Tuple `[value, helpers]`.\n */\nexport function useToggle(initial = false): [boolean, ToggleHelpers] {\n const [value, setValue] = useState<boolean>(initial);\n\n const toggle = useCallback((): void => setValue((current) => !current), []);\n const setTrue = useCallback((): void => setValue(true), []);\n const setFalse = useCallback((): void => setValue(false), []);\n const set = useCallback((next: boolean): void => setValue(next), []);\n\n return [value, { toggle, setTrue, setFalse, set }];\n}\n"],"mappings":"uBAeA,SAAgB,EAAU,EAAU,GAAiC,CACjE,GAAM,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAkB,CAAO,EAOnD,MAAO,CAAC,EAAO,CAAE,QAAA,EALF,EAAA,YAAA,KAAwB,EAAU,GAAY,CAAC,CAAO,EAAG,CAAC,CAKxD,EAAQ,SAAA,EAJT,EAAA,YAAA,KAAwB,EAAS,EAAI,EAAG,CAAC,CAIhC,EAAS,UAAA,EAHjB,EAAA,YAAA,KAAwB,EAAS,EAAK,EAAG,CAAC,CAGzB,EAAU,KAAA,EAFhC,EAAA,YAAA,CAAa,GAAwB,EAAS,CAAI,EAAG,CAAC,CAEtB,CAAI,CAAC,CACrD"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-window-size.cjs","names":[],"sources":["../../src/hooks/use-window-size.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport interface WindowSize {\n width: number;\n height: number;\n}\n\n/**\n * Reactive window dimensions. SSR-safe — returns `{ width: 0, height: 0 }`\n * until the first client render.\n *\n * @example\n * const { width, height } = useWindowSize();\n * const columns = width < 640 ? 1 : width < 1024 ? 2 : 3;\n */\nexport function useWindowSize(): WindowSize {\n const [size, setSize] = useState<WindowSize>(() =>\n typeof window === \"undefined\"\n ? { width: 0, height: 0 }\n : { width: window.innerWidth, height: window.innerHeight },\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const onResize = (): void =>\n setSize({ width: window.innerWidth, height: window.innerHeight });\n onResize();\n window.addEventListener(\"resize\", onResize, { passive: true });\n return () => window.removeEventListener(\"resize\", onResize);\n }, []);\n\n return size;\n}\n"],"mappings":"uBAeA,SAAgB,GAA4B,CACxC,GAAM,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,KACT,OAAO,OAAW,IACZ,CAAE,MAAO,EAAG,OAAQ,CAAE,EACtB,CAAE,MAAO,OAAO,WAAY,OAAQ,OAAO,WAAY,CACjE,EAWA,OATA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,MACF,EAAQ,CAAE,MAAO,OAAO,WAAY,OAAQ,OAAO,WAAY,CAAC,EAGpE,OAFA,EAAS,EACT,OAAO,iBAAiB,SAAU,EAAU,CAAE,QAAS,EAAK,CAAC,MAChD,OAAO,oBAAoB,SAAU,CAAQ,CAC9D,EAAG,CAAC,CAAC,EAEE,CACX"}
1
+ {"version":3,"file":"use-window-size.cjs","names":[],"sources":["../../src/hooks/use-window-size.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport interface WindowSize {\n width: number;\n height: number;\n}\n\n/**\n * Reactive window dimensions. SSR-safe — returns `{ width: 0, height: 0 }`\n * until the first client render.\n *\n * @example\n * const { width, height } = useWindowSize();\n * const columns = width < 640 ? 1 : width < 1024 ? 2 : 3;\n */\nexport function useWindowSize(): WindowSize {\n const [size, setSize] = useState<WindowSize>(() =>\n typeof window === \"undefined\"\n ? { width: 0, height: 0 }\n : { width: window.innerWidth, height: window.innerHeight },\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const onResize = (): void =>\n setSize({ width: window.innerWidth, height: window.innerHeight });\n onResize();\n window.addEventListener(\"resize\", onResize, { passive: true });\n return () => window.removeEventListener(\"resize\", onResize);\n }, []);\n\n return size;\n}\n"],"mappings":"uBAeA,SAAgB,GAA4B,CACxC,GAAM,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,KACpB,OAAO,OAAW,IACZ,CAAE,MAAO,EAAG,OAAQ,CAAE,EACtB,CAAE,MAAO,OAAO,WAAY,OAAQ,OAAO,WAAY,CACjE,EAWA,OATA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,MACF,EAAQ,CAAE,MAAO,OAAO,WAAY,OAAQ,OAAO,WAAY,CAAC,EAGpE,OAFA,EAAS,EACT,OAAO,iBAAiB,SAAU,EAAU,CAAE,QAAS,EAAK,CAAC,MAChD,OAAO,oBAAoB,SAAU,CAAQ,CAC9D,EAAG,CAAC,CAAC,EAEE,CACX"}
@@ -1,2 +1,2 @@
1
- const e=require("../utils/ids.cjs"),t=require("./errors.cjs");function n(e,t,n){let r=new URL(t,e.endsWith(`/`)?e:`${e}/`);if(n)for(let[e,t]of Object.entries(n))t!=null&&r.searchParams.set(e,String(t));return r.toString()}function r(e){return typeof FormData<`u`&&e instanceof FormData}async function i(e,n){let r;try{r=await e.clone().json()}catch{try{r=await e.text()}catch{r=null}}return new t.TempestApiError(t.buildApiError(e.status,r,e.headers,n))}function a(t){let a=t.fetcher??globalThis.fetch.bind(globalThis);function o(){let e=t.getToken?.();return e?{Authorization:`Bearer ${e}`}:{}}async function s(e,i,s){let{body:c,params:l,headers:u,...d}=i,f=r(c),p={...f?{}:{"Content-Type":`application/json`},...s?{"X-Request-ID":s}:{},...t.headers,...o(),...u},m={...d,headers:p,credentials:t.withCredentials?`include`:d.credentials,body:c==null?void 0:f?c:JSON.stringify(c)};return a(n(t.baseURL,e,l),m)}async function c(n,r={}){let a=t.requestId?t.requestId():e.randomId(),o=await s(n,r,a);if(o.status===401)if(t.refresh)try{await t.refresh(),o=await s(n,r,a)}catch{throw await t.onUnauthorized?.(o),await i(o,a)}else await t.onUnauthorized?.(o);if(!o.ok)throw await i(o,a);if(o.status!==204)return(o.headers.get(`content-type`)??``).includes(`application/json`)?await o.json():await o.text()}async function l(e,t,n=`POST`){return c(e,{method:n,body:t})}return{request:c,get:(e,t)=>c(e,{...t,method:`GET`}),post:(e,t)=>c(e,{...t,method:`POST`}),put:(e,t)=>c(e,{...t,method:`PUT`}),patch:(e,t)=>c(e,{...t,method:`PATCH`}),delete:(e,t)=>c(e,{...t,method:`DELETE`}),upload:l}}exports.createApiClient=a;
1
+ const e=require("../utils/ids.cjs"),t=require("./errors.cjs");function n(e,t,n){let r=new URL(t,e.endsWith(`/`)?e:`${e}/`);if(n)for(let[e,t]of Object.entries(n))t!=null&&r.searchParams.set(e,String(t));return r.toString()}function r(e){return typeof FormData<`u`&&e instanceof FormData}async function i(e,n){let r;try{r=await e.clone().json()}catch{try{r=await e.text()}catch{r=null}}return new t.TempestApiError(t.buildApiError(e.status,r,e.headers,n))}function a(t){let a=t.fetcher??globalThis.fetch.bind(globalThis);function o(){let e=t.getToken?.();return e?{Authorization:`Bearer ${e}`}:{}}async function s(e,i,s){let{body:c,params:l,headers:u,...d}=i,f=r(c),p={...f?{}:{"Content-Type":`application/json`},...s?{"X-Request-ID":s}:{},...t.headers,...o(),...u},m={...d,headers:p,credentials:t.withCredentials?`include`:d.credentials,body:c==null?void 0:f?c:JSON.stringify(c)};return a(n(t.baseURL,e,l),m)}async function c(n,r={}){let a=t.requestId?t.requestId():e.randomId(),o=await s(n,r,a);if(o.status===401){if(t.refresh)try{await t.refresh(),o=await s(n,r,a)}catch{throw await t.onUnauthorized?.(o),await i(o,a)}else await t.onUnauthorized?.(o)}if(!o.ok)throw await i(o,a);if(o.status!==204)return(o.headers.get(`content-type`)??``).includes(`application/json`)?await o.json():await o.text()}async function l(e,t,n=`POST`){return c(e,{method:n,body:t})}return{request:c,get:(e,t)=>c(e,{...t,method:`GET`}),post:(e,t)=>c(e,{...t,method:`POST`}),put:(e,t)=>c(e,{...t,method:`PUT`}),patch:(e,t)=>c(e,{...t,method:`PATCH`}),delete:(e,t)=>c(e,{...t,method:`DELETE`}),upload:l}}exports.createApiClient=a;
2
2
  //# sourceMappingURL=api-client.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-client.cjs","names":[],"sources":["../../src/http/api-client.ts"],"sourcesContent":["/**\n * @tempest-limits function-lines — createApiClient is three lines over the limit and\n * every one of them is a request-lifecycle concern the client cannot delegate: base\n * URL joining, the auth header, the retry loop, the timeout signal and the response\n * parsing that turns a failure into a typed error.\n */\nimport { randomId } from \"../utils\";\nimport { buildApiError, TempestApiError } from \"./errors\";\nimport type { ApiClient, ApiClientConfig, RequestOptions } from \"./types\";\n\nfunction buildUrl(baseURL: string, path: string, params?: RequestOptions[\"params\"]): string {\n const url = new URL(path, baseURL.endsWith(\"/\") ? baseURL : `${baseURL}/`);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n}\n\nfunction isFormData(body: unknown): body is FormData {\n return typeof FormData !== \"undefined\" && body instanceof FormData;\n}\n\nasync function parseError(response: Response, sentRequestId?: string): Promise<TempestApiError> {\n let body: unknown;\n try {\n body = await response.clone().json();\n } catch {\n try {\n body = await response.text();\n } catch {\n body = null;\n }\n }\n return new TempestApiError(\n buildApiError(response.status, body, response.headers, sentRequestId),\n );\n}\n\n/**\n * Create a typed HTTP client backed by `fetch`.\n *\n * Handles JSON serialization, query params, bearer auth via `getToken`,\n * automatic refresh + retry on 401 when `refresh` is supplied, and uploads\n * via `FormData`. Throws an `ApiError` on non-2xx responses.\n */\nexport function createApiClient(config: ApiClientConfig): ApiClient {\n const fetcher = config.fetcher ?? globalThis.fetch.bind(globalThis);\n\n function authHeaders(): Record<string, string> {\n const token = config.getToken?.();\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n\n async function rawRequest(\n path: string,\n options: RequestOptions,\n requestId?: string,\n ): Promise<Response> {\n const { body, params, headers, ...rest } = options;\n const isForm = isFormData(body);\n\n const finalHeaders: Record<string, string> = {\n ...(isForm ? {} : { \"Content-Type\": \"application/json\" }),\n ...(requestId ? { \"X-Request-ID\": requestId } : {}),\n ...config.headers,\n ...authHeaders(),\n ...(headers as Record<string, string> | undefined),\n };\n\n const init: RequestInit = {\n ...rest,\n headers: finalHeaders,\n credentials: config.withCredentials ? \"include\" : rest.credentials,\n body:\n body === undefined || body === null\n ? undefined\n : isForm\n ? (body as FormData)\n : JSON.stringify(body),\n };\n\n return fetcher(buildUrl(config.baseURL, path, params), init);\n }\n\n async function request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const requestId = config.requestId ? config.requestId() : randomId();\n let response = await rawRequest(path, options, requestId);\n\n if (response.status === 401) {\n if (config.refresh) {\n try {\n await config.refresh();\n response = await rawRequest(path, options, requestId);\n } catch {\n await config.onUnauthorized?.(response);\n throw await parseError(response, requestId);\n }\n } else {\n await config.onUnauthorized?.(response);\n }\n }\n\n if (!response.ok) {\n throw await parseError(response, requestId);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n return (await response.json()) as T;\n }\n return (await response.text()) as unknown as T;\n }\n\n async function upload<T>(\n path: string,\n formData: FormData,\n method: \"POST\" | \"PUT\" | \"PATCH\" = \"POST\",\n ): Promise<T> {\n return request<T>(path, { method, body: formData });\n }\n\n return {\n request,\n get: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"GET\" }),\n post: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"POST\" }),\n put: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"PUT\" }),\n patch: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"PATCH\" }),\n delete: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"DELETE\" }),\n upload,\n };\n}\n"],"mappings":"8DAUA,SAAS,EAAS,EAAiB,EAAc,EAA2C,CACxF,IAAM,EAAM,IAAI,IAAI,EAAM,EAAQ,SAAS,GAAG,EAAI,EAAU,GAAG,EAAQ,EAAE,EACzE,GAAI,MACK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAM,EACxC,GAAiC,MACjC,EAAI,aAAa,IAAI,EAAK,OAAO,CAAK,CAAC,EAInD,OAAO,EAAI,SAAS,CACxB,CAEA,SAAS,EAAW,EAAiC,CACjD,OAAO,OAAO,SAAa,KAAe,aAAgB,QAC9D,CAEA,eAAe,EAAW,EAAoB,EAAkD,CAC5F,IAAI,EACJ,GAAI,CACA,EAAO,MAAM,EAAS,MAAM,CAAC,CAAC,KAAK,CACvC,MAAQ,CACJ,GAAI,CACA,EAAO,MAAM,EAAS,KAAK,CAC/B,MAAQ,CACJ,EAAO,IACX,CACJ,CACA,OAAO,IAAI,EAAA,gBACP,EAAA,cAAc,EAAS,OAAQ,EAAM,EAAS,QAAS,CAAa,CACxE,CACJ,CASA,SAAgB,EAAgB,EAAoC,CAChE,IAAM,EAAU,EAAO,SAAW,WAAW,MAAM,KAAK,UAAU,EAElE,SAAS,GAAsC,CAC3C,IAAM,EAAQ,EAAO,WAAW,EAChC,OAAO,EAAQ,CAAE,cAAe,UAAU,GAAQ,EAAI,CAAC,CAC3D,CAEA,eAAe,EACX,EACA,EACA,EACiB,CACjB,GAAM,CAAE,OAAM,SAAQ,UAAS,GAAG,GAAS,EACrC,EAAS,EAAW,CAAI,EAExB,EAAuC,CACzC,GAAI,EAAS,CAAC,EAAI,CAAE,eAAgB,kBAAmB,EACvD,GAAI,EAAY,CAAE,eAAgB,CAAU,EAAI,CAAC,EACjD,GAAG,EAAO,QACV,GAAG,EAAY,EACf,GAAI,CACR,EAEM,EAAoB,CACtB,GAAG,EACH,QAAS,EACT,YAAa,EAAO,gBAAkB,UAAY,EAAK,YACvD,KACI,GAA+B,KACzB,IAAA,GACA,EACG,EACD,KAAK,UAAU,CAAI,CACnC,EAEA,OAAO,EAAQ,EAAS,EAAO,QAAS,EAAM,CAAM,EAAG,CAAI,CAC/D,CAEA,eAAe,EAAW,EAAc,EAA0B,CAAC,EAAe,CAC9E,IAAM,EAAY,EAAO,UAAY,EAAO,UAAU,EAAI,EAAA,SAAS,EAC/D,EAAW,MAAM,EAAW,EAAM,EAAS,CAAS,EAExD,GAAI,EAAS,SAAW,IACpB,GAAI,EAAO,QACP,GAAI,CACA,MAAM,EAAO,QAAQ,EACrB,EAAW,MAAM,EAAW,EAAM,EAAS,CAAS,CACxD,MAAQ,CAEJ,MADA,MAAM,EAAO,iBAAiB,CAAQ,EAChC,MAAM,EAAW,EAAU,CAAS,CAC9C,MAEA,MAAM,EAAO,iBAAiB,CAAQ,EAI9C,GAAI,CAAC,EAAS,GACV,MAAM,MAAM,EAAW,EAAU,CAAS,EAG1C,KAAS,SAAW,IAQxB,OAJoB,EAAS,QAAQ,IAAI,cAAc,GAAK,GAAA,CAC5C,SAAS,kBAAkB,EAC/B,MAAM,EAAS,KAAK,EAExB,MAAM,EAAS,KAAK,CAChC,CAEA,eAAe,EACX,EACA,EACA,EAAmC,OACzB,CACV,OAAO,EAAW,EAAM,CAAE,SAAQ,KAAM,CAAS,CAAC,CACtD,CAEA,MAAO,CACH,UACA,KAAS,EAAc,IACnB,EAAW,EAAM,CAAE,GAAG,EAAS,OAAQ,KAAM,CAAC,EAClD,MAAU,EAAc,IACpB,EAAW,EAAM,CAAE,GAAG,EAAS,OAAQ,MAAO,CAAC,EACnD,KAAS,EAAc,IACnB,EAAW,EAAM,CAAE,GAAG,EAAS,OAAQ,KAAM,CAAC,EAClD,OAAW,EAAc,IACrB,EAAW,EAAM,CAAE,GAAG,EAAS,OAAQ,OAAQ,CAAC,EACpD,QAAY,EAAc,IACtB,EAAW,EAAM,CAAE,GAAG,EAAS,OAAQ,QAAS,CAAC,EACrD,QACJ,CACJ"}
1
+ {"version":3,"file":"api-client.cjs","names":[],"sources":["../../src/http/api-client.ts"],"sourcesContent":["/**\n * @tempest-limits function-lines — createApiClient is three lines over the limit and\n * every one of them is a request-lifecycle concern the client cannot delegate: base\n * URL joining, the auth header, the retry loop, the timeout signal and the response\n * parsing that turns a failure into a typed error.\n */\nimport { randomId } from \"../utils\";\nimport { buildApiError, TempestApiError } from \"./errors\";\nimport type { ApiClient, ApiClientConfig, RequestOptions } from \"./types\";\n\nfunction buildUrl(baseURL: string, path: string, params?: RequestOptions[\"params\"]): string {\n const url = new URL(path, baseURL.endsWith(\"/\") ? baseURL : `${baseURL}/`);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n}\n\nfunction isFormData(body: unknown): body is FormData {\n return typeof FormData !== \"undefined\" && body instanceof FormData;\n}\n\nasync function parseError(response: Response, sentRequestId?: string): Promise<TempestApiError> {\n let body: unknown;\n try {\n body = await response.clone().json();\n } catch {\n try {\n body = await response.text();\n } catch {\n body = null;\n }\n }\n return new TempestApiError(\n buildApiError(response.status, body, response.headers, sentRequestId),\n );\n}\n\n/**\n * Create a typed HTTP client backed by `fetch`.\n *\n * Handles JSON serialization, query params, bearer auth via `getToken`,\n * automatic refresh + retry on 401 when `refresh` is supplied, and uploads\n * via `FormData`. Throws an `ApiError` on non-2xx responses.\n */\nexport function createApiClient(config: ApiClientConfig): ApiClient {\n const fetcher = config.fetcher ?? globalThis.fetch.bind(globalThis);\n\n function authHeaders(): Record<string, string> {\n const token = config.getToken?.();\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n\n async function rawRequest(\n path: string,\n options: RequestOptions,\n requestId?: string,\n ): Promise<Response> {\n const { body, params, headers, ...rest } = options;\n const isForm = isFormData(body);\n\n const finalHeaders: Record<string, string> = {\n ...(isForm ? {} : { \"Content-Type\": \"application/json\" }),\n ...(requestId ? { \"X-Request-ID\": requestId } : {}),\n ...config.headers,\n ...authHeaders(),\n ...(headers as Record<string, string> | undefined),\n };\n\n const init: RequestInit = {\n ...rest,\n headers: finalHeaders,\n credentials: config.withCredentials ? \"include\" : rest.credentials,\n body:\n body === undefined || body === null\n ? undefined\n : isForm\n ? (body as FormData)\n : JSON.stringify(body),\n };\n\n return fetcher(buildUrl(config.baseURL, path, params), init);\n }\n\n async function request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const requestId = config.requestId ? config.requestId() : randomId();\n let response = await rawRequest(path, options, requestId);\n\n if (response.status === 401) {\n if (config.refresh) {\n try {\n await config.refresh();\n response = await rawRequest(path, options, requestId);\n } catch {\n await config.onUnauthorized?.(response);\n throw await parseError(response, requestId);\n }\n } else {\n await config.onUnauthorized?.(response);\n }\n }\n\n if (!response.ok) {\n throw await parseError(response, requestId);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n return (await response.json()) as T;\n }\n return (await response.text()) as unknown as T;\n }\n\n async function upload<T>(\n path: string,\n formData: FormData,\n method: \"POST\" | \"PUT\" | \"PATCH\" = \"POST\",\n ): Promise<T> {\n return request<T>(path, { method, body: formData });\n }\n\n return {\n request,\n get: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"GET\" }),\n post: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"POST\" }),\n put: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"PUT\" }),\n patch: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"PATCH\" }),\n delete: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"DELETE\" }),\n upload,\n };\n}\n"],"mappings":"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"}
@@ -45,12 +45,14 @@ function o(t) {
45
45
  }
46
46
  async function c(n, r = {}) {
47
47
  let i = t.requestId ? t.requestId() : e(), o = await s(n, r, i);
48
- if (o.status === 401) if (t.refresh) try {
49
- await t.refresh(), o = await s(n, r, i);
50
- } catch {
51
- throw await t.onUnauthorized?.(o), await a(o, i);
48
+ if (o.status === 401) {
49
+ if (t.refresh) try {
50
+ await t.refresh(), o = await s(n, r, i);
51
+ } catch {
52
+ throw await t.onUnauthorized?.(o), await a(o, i);
53
+ }
54
+ else await t.onUnauthorized?.(o);
52
55
  }
53
- else await t.onUnauthorized?.(o);
54
56
  if (!o.ok) throw await a(o, i);
55
57
  if (o.status !== 204) return (o.headers.get("content-type") ?? "").includes("application/json") ? await o.json() : await o.text();
56
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"api-client.js","names":[],"sources":["../../src/http/api-client.ts"],"sourcesContent":["/**\n * @tempest-limits function-lines — createApiClient is three lines over the limit and\n * every one of them is a request-lifecycle concern the client cannot delegate: base\n * URL joining, the auth header, the retry loop, the timeout signal and the response\n * parsing that turns a failure into a typed error.\n */\nimport { randomId } from \"../utils\";\nimport { buildApiError, TempestApiError } from \"./errors\";\nimport type { ApiClient, ApiClientConfig, RequestOptions } from \"./types\";\n\nfunction buildUrl(baseURL: string, path: string, params?: RequestOptions[\"params\"]): string {\n const url = new URL(path, baseURL.endsWith(\"/\") ? baseURL : `${baseURL}/`);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n}\n\nfunction isFormData(body: unknown): body is FormData {\n return typeof FormData !== \"undefined\" && body instanceof FormData;\n}\n\nasync function parseError(response: Response, sentRequestId?: string): Promise<TempestApiError> {\n let body: unknown;\n try {\n body = await response.clone().json();\n } catch {\n try {\n body = await response.text();\n } catch {\n body = null;\n }\n }\n return new TempestApiError(\n buildApiError(response.status, body, response.headers, sentRequestId),\n );\n}\n\n/**\n * Create a typed HTTP client backed by `fetch`.\n *\n * Handles JSON serialization, query params, bearer auth via `getToken`,\n * automatic refresh + retry on 401 when `refresh` is supplied, and uploads\n * via `FormData`. Throws an `ApiError` on non-2xx responses.\n */\nexport function createApiClient(config: ApiClientConfig): ApiClient {\n const fetcher = config.fetcher ?? globalThis.fetch.bind(globalThis);\n\n function authHeaders(): Record<string, string> {\n const token = config.getToken?.();\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n\n async function rawRequest(\n path: string,\n options: RequestOptions,\n requestId?: string,\n ): Promise<Response> {\n const { body, params, headers, ...rest } = options;\n const isForm = isFormData(body);\n\n const finalHeaders: Record<string, string> = {\n ...(isForm ? {} : { \"Content-Type\": \"application/json\" }),\n ...(requestId ? { \"X-Request-ID\": requestId } : {}),\n ...config.headers,\n ...authHeaders(),\n ...(headers as Record<string, string> | undefined),\n };\n\n const init: RequestInit = {\n ...rest,\n headers: finalHeaders,\n credentials: config.withCredentials ? \"include\" : rest.credentials,\n body:\n body === undefined || body === null\n ? undefined\n : isForm\n ? (body as FormData)\n : JSON.stringify(body),\n };\n\n return fetcher(buildUrl(config.baseURL, path, params), init);\n }\n\n async function request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const requestId = config.requestId ? config.requestId() : randomId();\n let response = await rawRequest(path, options, requestId);\n\n if (response.status === 401) {\n if (config.refresh) {\n try {\n await config.refresh();\n response = await rawRequest(path, options, requestId);\n } catch {\n await config.onUnauthorized?.(response);\n throw await parseError(response, requestId);\n }\n } else {\n await config.onUnauthorized?.(response);\n }\n }\n\n if (!response.ok) {\n throw await parseError(response, requestId);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n return (await response.json()) as T;\n }\n return (await response.text()) as unknown as T;\n }\n\n async function upload<T>(\n path: string,\n formData: FormData,\n method: \"POST\" | \"PUT\" | \"PATCH\" = \"POST\",\n ): Promise<T> {\n return request<T>(path, { method, body: formData });\n }\n\n return {\n request,\n get: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"GET\" }),\n post: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"POST\" }),\n put: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"PUT\" }),\n patch: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"PATCH\" }),\n delete: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"DELETE\" }),\n upload,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"api-client.js","names":[],"sources":["../../src/http/api-client.ts"],"sourcesContent":["/**\n * @tempest-limits function-lines — createApiClient is three lines over the limit and\n * every one of them is a request-lifecycle concern the client cannot delegate: base\n * URL joining, the auth header, the retry loop, the timeout signal and the response\n * parsing that turns a failure into a typed error.\n */\nimport { randomId } from \"../utils\";\nimport { buildApiError, TempestApiError } from \"./errors\";\nimport type { ApiClient, ApiClientConfig, RequestOptions } from \"./types\";\n\nfunction buildUrl(baseURL: string, path: string, params?: RequestOptions[\"params\"]): string {\n const url = new URL(path, baseURL.endsWith(\"/\") ? baseURL : `${baseURL}/`);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n}\n\nfunction isFormData(body: unknown): body is FormData {\n return typeof FormData !== \"undefined\" && body instanceof FormData;\n}\n\nasync function parseError(response: Response, sentRequestId?: string): Promise<TempestApiError> {\n let body: unknown;\n try {\n body = await response.clone().json();\n } catch {\n try {\n body = await response.text();\n } catch {\n body = null;\n }\n }\n return new TempestApiError(\n buildApiError(response.status, body, response.headers, sentRequestId),\n );\n}\n\n/**\n * Create a typed HTTP client backed by `fetch`.\n *\n * Handles JSON serialization, query params, bearer auth via `getToken`,\n * automatic refresh + retry on 401 when `refresh` is supplied, and uploads\n * via `FormData`. Throws an `ApiError` on non-2xx responses.\n */\nexport function createApiClient(config: ApiClientConfig): ApiClient {\n const fetcher = config.fetcher ?? globalThis.fetch.bind(globalThis);\n\n function authHeaders(): Record<string, string> {\n const token = config.getToken?.();\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n\n async function rawRequest(\n path: string,\n options: RequestOptions,\n requestId?: string,\n ): Promise<Response> {\n const { body, params, headers, ...rest } = options;\n const isForm = isFormData(body);\n\n const finalHeaders: Record<string, string> = {\n ...(isForm ? {} : { \"Content-Type\": \"application/json\" }),\n ...(requestId ? { \"X-Request-ID\": requestId } : {}),\n ...config.headers,\n ...authHeaders(),\n ...(headers as Record<string, string> | undefined),\n };\n\n const init: RequestInit = {\n ...rest,\n headers: finalHeaders,\n credentials: config.withCredentials ? \"include\" : rest.credentials,\n body:\n body === undefined || body === null\n ? undefined\n : isForm\n ? (body as FormData)\n : JSON.stringify(body),\n };\n\n return fetcher(buildUrl(config.baseURL, path, params), init);\n }\n\n async function request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const requestId = config.requestId ? config.requestId() : randomId();\n let response = await rawRequest(path, options, requestId);\n\n if (response.status === 401) {\n if (config.refresh) {\n try {\n await config.refresh();\n response = await rawRequest(path, options, requestId);\n } catch {\n await config.onUnauthorized?.(response);\n throw await parseError(response, requestId);\n }\n } else {\n await config.onUnauthorized?.(response);\n }\n }\n\n if (!response.ok) {\n throw await parseError(response, requestId);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n return (await response.json()) as T;\n }\n return (await response.text()) as unknown as T;\n }\n\n async function upload<T>(\n path: string,\n formData: FormData,\n method: \"POST\" | \"PUT\" | \"PATCH\" = \"POST\",\n ): Promise<T> {\n return request<T>(path, { method, body: formData });\n }\n\n return {\n request,\n get: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"GET\" }),\n post: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"POST\" }),\n put: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"PUT\" }),\n patch: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"PATCH\" }),\n delete: <T>(path: string, options?: RequestOptions) =>\n request<T>(path, { ...options, method: \"DELETE\" }),\n upload,\n };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("./errors.cjs"),t=require("./idempotency.cjs"),n=require("./retry.cjs");var r=`1.0.0`,i=5*1024*1024;function a(e){let t=new TextEncoder().encode(e),n=``;for(let e of t)n+=String.fromCharCode(e);return btoa(n)}function o(e){if(!e)return null;let t=Object.entries(e).map(([e,t])=>`${e} ${a(t)}`);return t.length>0?t.join(`,`):null}function s(e,t){let n=t,r=typeof n.name==`string`?n.name:`blob`,i=typeof n.lastModified==`number`?n.lastModified:0;return`${e}|${r}|${t.size}|${t.type}|${i}`}function c(e=`tempest-upload:`){function t(){try{return typeof localStorage>`u`?null:localStorage}catch{return null}}return{get(n){let r=t()?.getItem(e+n);if(!r)return null;try{return JSON.parse(r)}catch{return null}},set(n,r){t()?.setItem(e+n,JSON.stringify(r))},delete(n){t()?.removeItem(e+n)}}}function l(t){return new Promise((n,r)=>{let i=new XMLHttpRequest;i.open(t.method,t.url),i.withCredentials=t.withCredentials;for(let[e,n]of Object.entries(t.headers))i.setRequestHeader(e,n);if(t.onProgress){let e=t.onProgress;i.upload.onprogress=t=>e(t.loaded)}i.onload=()=>n({status:i.status,text:i.responseText,header:e=>i.getResponseHeader(e)}),i.onerror=()=>r(new e.TempestApiError({status:0,detail:`Falha de rede no upload resumível.`})),i.onabort=()=>r(new DOMException(`Aborted`,`AbortError`)),t.register(i),i.send(t.body)})}function u(e){let t=e.header(`Upload-Offset`);if(t===null)return null;let n=Number(t);return Number.isFinite(n)&&n>=0?n:null}function d(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function f(t,n){let r=d(t.text),i=e.buildApiError(t.status,r,{get:t.header}),a=typeof r==`object`&&!!r&&(`detail`in r||`message`in r);return new e.TempestApiError({...i,detail:a?i.detail:n})}function p(e){let t=typeof window>`u`?void 0:window.location.href;try{return new URL(e,t).href}catch{return e}}function m(a){let{endpoint:d,file:m,chunkSize:h=i,metadata:g,headers:_={},getToken:v,withCredentials:y=!1,key:b=s(d,m),storage:x=c(),retry:S,onProgress:C,onStateChange:w}=a,T=`idle`,E=0,D=null,O=null,k=null,A=null,j=0;function M(e){T!==e&&(T=e,w?.(e))}function N(e){C?.({loaded:e,total:m.size,fraction:m.size===0?1:e/m.size,resumedFrom:j})}function P(){let e={..._,"Tus-Resumable":r},t=v?.();return t&&!(`Authorization`in e)&&(e.Authorization=`Bearer ${t}`),e}function F(e){A=e}async function I(){!x||!D||!O||await x.set(b,{url:D,offset:E,size:m.size,idempotencyKey:O,updatedAt:Date.now()})}async function L(t){let n=await l({method:`HEAD`,url:t,headers:P(),withCredentials:y,register:F});if(n.status===404||n.status===410)throw new e.TempestApiError({status:n.status,detail:`O upload expirou no servidor. Comece de novo.`});let r=u(n);if(r===null)throw f(n,`HEAD sem Upload-Offset.`);return r}async function R(){let e=x?await x.get(b):null;if(e&&e.size===m.size&&(O=e.idempotencyKey,e.url))try{return E=await L(e.url),D=e.url,e.url}catch{E=0}M(`creating`),O??=t.generateIdempotencyKey(),D=null,E=0,x&&await x.set(b,{url:``,offset:0,size:m.size,idempotencyKey:O,updatedAt:Date.now()});let n={...P(),"Upload-Length":String(m.size),"Idempotency-Key":O},r=o(g);r&&(n[`Upload-Metadata`]=r);let i=await l({method:`POST`,url:d,headers:n,withCredentials:y,register:F});if(i.status!==201)throw f(i,`Criação do upload recusada.`);let a=i.header(`Location`);if(!a)throw f(i,`Criação do upload sem cabeçalho Location.`);return D=p(a),await I(),D}async function z(e,t){if(t.needed&&(E=await L(e),t.needed=!1,N(E),await I(),E>=m.size))return;let n=Math.min(E+h,m.size),r=E,i=await l({method:`PATCH`,url:e,headers:{...P(),"Content-Type":`application/offset+octet-stream`,"Upload-Offset":String(r)},body:m.slice(r,n),withCredentials:y,onProgress:e=>N(Math.min(r+e,m.size)),register:F});if(i.status===409||i.status===412)throw t.needed=!0,f(i,`Offset divergente — o servidor já tinha esses bytes.`);if(i.status!==204&&i.status!==200)throw f(i,`Chunk recusado pelo servidor.`);E=u(i)??n,N(E),await I()}async function B(){k=null;let e=await R();j=E,M(`uploading`),N(E);let t={needed:!1};for(;E<m.size&&!k;)await n.retry(()=>z(e,t),{retries:5,...S,shouldRetry:(e,n)=>k||e instanceof DOMException&&e.name===`AbortError`?!1:(t.needed=!0,S?.shouldRetry?.(e,n)??!0)});return k===`pause`?(M(`paused`),null):k===`abort`?(M(`aborted`),null):(M(`done`),x&&await x.delete(b),{url:e,size:m.size})}async function V(){try{return await B()}catch(e){if(k!==null||e instanceof DOMException&&e.name===`AbortError`)return M(k===`abort`?`aborted`:`paused`),null;throw M(`error`),e}finally{A=null}}function H(e){k=e,A?.abort(),A=null}return{start:V,resume:V,pause:()=>H(`pause`),abort:async({discard:e=!1}={})=>{H(`abort`),M(`aborted`),e&&(D&&await l({method:`DELETE`,url:D,headers:P(),withCredentials:y,register:()=>void 0}).catch(()=>void 0),x&&await x.delete(b))},get state(){return T},get offset(){return E},get url(){return D},key:b}}exports.DEFAULT_CHUNK_SIZE=i,exports.TUS_VERSION=r,exports.createLocalUploadStorage=c,exports.createResumableUpload=m,exports.uploadFingerprint=s;
1
+ const e=require("./errors.cjs"),t=require("./idempotency.cjs"),n=require("./retry.cjs");var r=`1.0.0`,i=5242880;function a(e){let t=new TextEncoder().encode(e),n=``;for(let e of t)n+=String.fromCharCode(e);return btoa(n)}function o(e){if(!e)return null;let t=Object.entries(e).map(([e,t])=>`${e} ${a(t)}`);return t.length>0?t.join(`,`):null}function s(e,t){let n=t,r=typeof n.name==`string`?n.name:`blob`,i=typeof n.lastModified==`number`?n.lastModified:0;return`${e}|${r}|${t.size}|${t.type}|${i}`}function c(e=`tempest-upload:`){function t(){try{return typeof localStorage>`u`?null:localStorage}catch{return null}}return{get(n){let r=t()?.getItem(e+n);if(!r)return null;try{return JSON.parse(r)}catch{return null}},set(n,r){t()?.setItem(e+n,JSON.stringify(r))},delete(n){t()?.removeItem(e+n)}}}function l(t){return new Promise((n,r)=>{let i=new XMLHttpRequest;i.open(t.method,t.url),i.withCredentials=t.withCredentials;for(let[e,n]of Object.entries(t.headers))i.setRequestHeader(e,n);if(t.onProgress){let e=t.onProgress;i.upload.onprogress=t=>e(t.loaded)}i.onload=()=>n({status:i.status,text:i.responseText,header:e=>i.getResponseHeader(e)}),i.onerror=()=>r(new e.TempestApiError({status:0,detail:`Falha de rede no upload resumível.`})),i.onabort=()=>r(new DOMException(`Aborted`,`AbortError`)),t.register(i),i.send(t.body)})}function u(e){let t=e.header(`Upload-Offset`);if(t===null)return null;let n=Number(t);return Number.isFinite(n)&&n>=0?n:null}function d(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function f(t,n){let r=d(t.text),i=e.buildApiError(t.status,r,{get:t.header}),a=typeof r==`object`&&!!r&&(`detail`in r||`message`in r);return new e.TempestApiError({...i,detail:a?i.detail:n})}function p(e){let t=typeof window>`u`?void 0:window.location.href;try{return new URL(e,t).href}catch{return e}}function m(a){let{endpoint:d,file:m,chunkSize:h=i,metadata:g,headers:_={},getToken:v,withCredentials:y=!1,key:b=s(d,m),storage:x=c(),retry:S,onProgress:C,onStateChange:w}=a,T=`idle`,E=0,D=null,O=null,k=null,A=null,j=0;function M(e){T!==e&&(T=e,w?.(e))}function N(e){C?.({loaded:e,total:m.size,fraction:m.size===0?1:e/m.size,resumedFrom:j})}function P(){let e={..._,"Tus-Resumable":r},t=v?.();return t&&!(`Authorization`in e)&&(e.Authorization=`Bearer ${t}`),e}function F(e){A=e}async function I(){!x||!D||!O||await x.set(b,{url:D,offset:E,size:m.size,idempotencyKey:O,updatedAt:Date.now()})}async function L(t){let n=await l({method:`HEAD`,url:t,headers:P(),withCredentials:y,register:F});if(n.status===404||n.status===410)throw new e.TempestApiError({status:n.status,detail:`O upload expirou no servidor. Comece de novo.`});let r=u(n);if(r===null)throw f(n,`HEAD sem Upload-Offset.`);return r}async function R(){let e=x?await x.get(b):null;if(e&&e.size===m.size&&(O=e.idempotencyKey,e.url))try{return E=await L(e.url),D=e.url,e.url}catch{E=0}M(`creating`),O??=t.generateIdempotencyKey(),D=null,E=0,x&&await x.set(b,{url:``,offset:0,size:m.size,idempotencyKey:O,updatedAt:Date.now()});let n={...P(),"Upload-Length":String(m.size),"Idempotency-Key":O},r=o(g);r&&(n[`Upload-Metadata`]=r);let i=await l({method:`POST`,url:d,headers:n,withCredentials:y,register:F});if(i.status!==201)throw f(i,`Criação do upload recusada.`);let a=i.header(`Location`);if(!a)throw f(i,`Criação do upload sem cabeçalho Location.`);return D=p(a),await I(),D}async function z(e,t){if(t.needed&&(E=await L(e),t.needed=!1,N(E),await I(),E>=m.size))return;let n=Math.min(E+h,m.size),r=E,i=await l({method:`PATCH`,url:e,headers:{...P(),"Content-Type":`application/offset+octet-stream`,"Upload-Offset":String(r)},body:m.slice(r,n),withCredentials:y,onProgress:e=>N(Math.min(r+e,m.size)),register:F});if(i.status===409||i.status===412)throw t.needed=!0,f(i,`Offset divergente — o servidor já tinha esses bytes.`);if(i.status!==204&&i.status!==200)throw f(i,`Chunk recusado pelo servidor.`);E=u(i)??n,N(E),await I()}async function B(){k=null;let e=await R();j=E,M(`uploading`),N(E);let t={needed:!1};for(;E<m.size&&!k;)await n.retry(()=>z(e,t),{retries:5,...S,shouldRetry:(e,n)=>k||e instanceof DOMException&&e.name===`AbortError`?!1:(t.needed=!0,S?.shouldRetry?.(e,n)??!0)});return k===`pause`?(M(`paused`),null):k===`abort`?(M(`aborted`),null):(M(`done`),x&&await x.delete(b),{url:e,size:m.size})}async function V(){try{return await B()}catch(e){if(k!==null||e instanceof DOMException&&e.name===`AbortError`)return M(k===`abort`?`aborted`:`paused`),null;throw M(`error`),e}finally{A=null}}function H(e){k=e,A?.abort(),A=null}return{start:V,resume:V,pause:()=>H(`pause`),abort:async({discard:e=!1}={})=>{H(`abort`),M(`aborted`),e&&(D&&await l({method:`DELETE`,url:D,headers:P(),withCredentials:y,register:()=>void 0}).catch(()=>void 0),x&&await x.delete(b))},get state(){return T},get offset(){return E},get url(){return D},key:b}}exports.DEFAULT_CHUNK_SIZE=i,exports.TUS_VERSION=r,exports.createLocalUploadStorage=c,exports.createResumableUpload=m,exports.uploadFingerprint=s;
2
2
  //# sourceMappingURL=resumable-upload.cjs.map