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":"Command.js","names":[],"sources":["../../../src/components/Command/Command.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — a command palette is a filtered\n * listbox with its own keyboard contract: the body holds the query, the flattened\n * result list, the active index and the Escape/Enter handling, all of which read\n * each other on every keystroke.\n */\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport { useFocusTrap } from \"@/hooks/use-focus-trap\";\nimport styles from \"./Command.module.css\";\n\nexport interface CommandItem {\n /** Stable unique identifier for the item. */\n id: string;\n /** Human-readable label shown in the list and matched against the query. */\n label: string;\n /** Optional group heading; items sharing a group are rendered together. */\n group?: string;\n /** Extra terms matched against the query in addition to `label`. */\n keywords?: string[];\n /** Invoked when the item is chosen (click or Enter on the active row). */\n onSelect: () => void;\n /** Optional leading icon. */\n icon?: ReactNode;\n}\n\nexport interface CommandProps {\n /** Whether the palette is visible. */\n open: boolean;\n /** Called with the next open state (Escape, selection, backdrop click). */\n onOpenChange: (open: boolean) => void;\n /** Candidate items to filter and display. */\n items: CommandItem[];\n /** Placeholder for the search input. */\n placeholder?: string;\n /** Rendered when no item matches the current query. */\n emptyMessage?: ReactNode;\n /** Forwarded to the dialog element. */\n className?: string;\n}\n\ninterface CommandGroup {\n name: string | undefined;\n items: CommandItem[];\n}\n\n/**\n * Case-insensitively test whether `item` matches `query` by substring against\n * its label and any keywords. An empty query matches everything.\n *\n * @param item - The candidate command item.\n * @param query - The lowercased search query.\n * @returns `true` when the item should be shown.\n */\nfunction matchesQuery(item: CommandItem, query: string): boolean {\n if (query === \"\") return true;\n if (item.label.toLowerCase().includes(query)) return true;\n return (item.keywords ?? []).some((keyword) => keyword.toLowerCase().includes(query));\n}\n\n/**\n * Partition a flat item list into ordered groups, preserving first-seen order\n * for both groups and the items within them.\n *\n * @param items - The (already filtered) items to group.\n * @returns An ordered list of groups.\n */\nfunction groupItems(items: CommandItem[]): CommandGroup[] {\n const groups: CommandGroup[] = [];\n const indexByName = new Map<string | undefined, number>();\n for (const item of items) {\n const existing = indexByName.get(item.group);\n if (existing === undefined) {\n indexByName.set(item.group, groups.length);\n groups.push({ name: item.group, items: [item] });\n } else {\n groups[existing]!.items.push(item);\n }\n }\n return groups;\n}\n\n/**\n * A ⌘K-style command palette: an overlay dialog with a search input that\n * substring-filters items by label and keywords, groups results, and supports\n * full keyboard navigation (Arrow up/down, Enter, Escape). Traps focus while\n * open.\n */\nexport function Command({\n open,\n onOpenChange,\n items,\n placeholder = \"Type a command…\",\n emptyMessage = \"No results\",\n className,\n}: CommandProps) {\n const dialogRef = useRef<HTMLDivElement>(null);\n const [query, setQuery] = useState<string>(\"\");\n const [activeIndex, setActiveIndex] = useState<number>(0);\n const listId = \"tempest-command-list\";\n\n useFocusTrap(dialogRef, open);\n\n const filtered = useMemo<CommandItem[]>(() => {\n const normalized = query.trim().toLowerCase();\n const visible = items.filter((item) => matchesQuery(item, normalized));\n return groupItems(visible).flatMap((group) => group.items);\n }, [items, query]);\n\n const groups = useMemo<CommandGroup[]>(() => groupItems(filtered), [filtered]);\n\n // Reset transient state whenever the palette opens.\n useEffect(() => {\n if (open) {\n setQuery(\"\");\n setActiveIndex(0);\n }\n }, [open]);\n\n // Keep the active index within bounds as the filtered list shrinks/grows.\n useEffect(() => {\n setActiveIndex((index) => {\n if (filtered.length === 0) return 0;\n return Math.min(index, filtered.length - 1);\n });\n }, [filtered.length]);\n\n if (!open || typeof document === \"undefined\") return null;\n\n function selectItem(item: CommandItem): void {\n item.onSelect();\n onOpenChange(false);\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {\n if (event.key === \"Escape\") {\n event.preventDefault();\n onOpenChange(false);\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index + 1) % filtered.length);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index - 1 + filtered.length) % filtered.length);\n return;\n }\n if (event.key === \"Enter\") {\n event.preventDefault();\n const item = filtered[activeIndex];\n if (item) selectItem(item);\n }\n }\n\n let renderIndex = -1;\n\n return createPortal(\n <div className={styles.overlay} role=\"presentation\" onClick={() => onOpenChange(false)}>\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command palette\"\n className={cn(styles.dialog, className)}\n onClick={(event) => event.stopPropagation()}\n >\n <div className={styles.inputRow}>\n <SearchIcon />\n <input\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n autoFocus\n className={styles.input}\n placeholder={placeholder}\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={handleKeyDown}\n />\n </div>\n <ul id={listId} role=\"listbox\" className={styles.list}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n groups.map((group) => (\n <li key={group.name ?? \"__ungrouped__\"} className={styles.group}>\n {group.name && (\n <div className={styles.groupHeading}>{group.name}</div>\n )}\n <ul role=\"presentation\" className={styles.groupList}>\n {group.items.map((item) => {\n renderIndex += 1;\n const isActive = renderIndex === activeIndex;\n const index = renderIndex;\n return (\n <li\n key={item.id}\n role=\"option\"\n aria-selected={isActive}\n className={cn(\n styles.option,\n isActive && styles.active,\n )}\n onMouseMove={() => setActiveIndex(index)}\n onClick={() => selectItem(item)}\n >\n {item.icon && (\n <span className={styles.icon}>{item.icon}</span>\n )}\n <span className={styles.label}>{item.label}</span>\n </li>\n );\n })}\n </ul>\n </li>\n ))\n )}\n </ul>\n </div>\n </div>,\n document.body,\n );\n}\n\nfunction SearchIcon() {\n return (\n <svg\n className={styles.searchIcon}\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M20 20l-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Command.js","names":[],"sources":["../../../src/components/Command/Command.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — a command palette is a filtered\n * listbox with its own keyboard contract: the body holds the query, the flattened\n * result list, the active index and the Escape/Enter handling, all of which read\n * each other on every keystroke.\n */\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"@/utils/cn\";\nimport { useFocusTrap } from \"@/hooks/use-focus-trap\";\nimport styles from \"./Command.module.css\";\n\nexport interface CommandItem {\n /** Stable unique identifier for the item. */\n id: string;\n /** Human-readable label shown in the list and matched against the query. */\n label: string;\n /** Optional group heading; items sharing a group are rendered together. */\n group?: string;\n /** Extra terms matched against the query in addition to `label`. */\n keywords?: string[];\n /** Invoked when the item is chosen (click or Enter on the active row). */\n onSelect: () => void;\n /** Optional leading icon. */\n icon?: ReactNode;\n}\n\nexport interface CommandProps {\n /** Whether the palette is visible. */\n open: boolean;\n /** Called with the next open state (Escape, selection, backdrop click). */\n onOpenChange: (open: boolean) => void;\n /** Candidate items to filter and display. */\n items: CommandItem[];\n /** Placeholder for the search input. */\n placeholder?: string;\n /** Rendered when no item matches the current query. */\n emptyMessage?: ReactNode;\n /** Forwarded to the dialog element. */\n className?: string;\n}\n\ninterface CommandGroup {\n name: string | undefined;\n items: CommandItem[];\n}\n\n/**\n * Case-insensitively test whether `item` matches `query` by substring against\n * its label and any keywords. An empty query matches everything.\n *\n * @param item - The candidate command item.\n * @param query - The lowercased search query.\n * @returns `true` when the item should be shown.\n */\nfunction matchesQuery(item: CommandItem, query: string): boolean {\n if (query === \"\") return true;\n if (item.label.toLowerCase().includes(query)) return true;\n return (item.keywords ?? []).some((keyword) => keyword.toLowerCase().includes(query));\n}\n\n/**\n * Partition a flat item list into ordered groups, preserving first-seen order\n * for both groups and the items within them.\n *\n * @param items - The (already filtered) items to group.\n * @returns An ordered list of groups.\n */\nfunction groupItems(items: CommandItem[]): CommandGroup[] {\n const groups: CommandGroup[] = [];\n const indexByName = new Map<string | undefined, number>();\n for (const item of items) {\n const existing = indexByName.get(item.group);\n if (existing === undefined) {\n indexByName.set(item.group, groups.length);\n groups.push({ name: item.group, items: [item] });\n } else {\n groups[existing]!.items.push(item);\n }\n }\n return groups;\n}\n\n/**\n * A ⌘K-style command palette: an overlay dialog with a search input that\n * substring-filters items by label and keywords, groups results, and supports\n * full keyboard navigation (Arrow up/down, Enter, Escape). Traps focus while\n * open.\n */\nexport function Command({\n open,\n onOpenChange,\n items,\n placeholder = \"Type a command…\",\n emptyMessage = \"No results\",\n className,\n}: CommandProps) {\n const dialogRef = useRef<HTMLDivElement>(null);\n const [query, setQuery] = useState<string>(\"\");\n const [activeIndex, setActiveIndex] = useState<number>(0);\n const listId = \"tempest-command-list\";\n\n useFocusTrap(dialogRef, open);\n\n const filtered = useMemo<CommandItem[]>(() => {\n const normalized = query.trim().toLowerCase();\n const visible = items.filter((item) => matchesQuery(item, normalized));\n return groupItems(visible).flatMap((group) => group.items);\n }, [items, query]);\n\n const groups = useMemo<CommandGroup[]>(() => groupItems(filtered), [filtered]);\n\n // Reset transient state whenever the palette opens.\n useEffect(() => {\n if (open) {\n setQuery(\"\");\n setActiveIndex(0);\n }\n }, [open]);\n\n // Keep the active index within bounds as the filtered list shrinks/grows.\n useEffect(() => {\n setActiveIndex((index) => {\n if (filtered.length === 0) return 0;\n return Math.min(index, filtered.length - 1);\n });\n }, [filtered.length]);\n\n if (!open || typeof document === \"undefined\") return null;\n\n function selectItem(item: CommandItem): void {\n item.onSelect();\n onOpenChange(false);\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {\n if (event.key === \"Escape\") {\n event.preventDefault();\n onOpenChange(false);\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index + 1) % filtered.length);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n if (filtered.length === 0) return;\n setActiveIndex((index) => (index - 1 + filtered.length) % filtered.length);\n return;\n }\n if (event.key === \"Enter\") {\n event.preventDefault();\n const item = filtered[activeIndex];\n if (item) selectItem(item);\n }\n }\n\n let renderIndex = -1;\n\n return createPortal(\n <div className={styles.overlay} role=\"presentation\" onClick={() => onOpenChange(false)}>\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command palette\"\n className={cn(styles.dialog, className)}\n onClick={(event) => event.stopPropagation()}\n >\n <div className={styles.inputRow}>\n <SearchIcon />\n <input\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n autoFocus\n className={styles.input}\n placeholder={placeholder}\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={handleKeyDown}\n />\n </div>\n <ul id={listId} role=\"listbox\" className={styles.list}>\n {filtered.length === 0 ? (\n <li className={styles.empty}>{emptyMessage}</li>\n ) : (\n groups.map((group) => (\n <li key={group.name ?? \"__ungrouped__\"} className={styles.group}>\n {group.name && (\n <div className={styles.groupHeading}>{group.name}</div>\n )}\n <ul role=\"presentation\" className={styles.groupList}>\n {group.items.map((item) => {\n renderIndex += 1;\n const isActive = renderIndex === activeIndex;\n const index = renderIndex;\n return (\n <li\n key={item.id}\n role=\"option\"\n aria-selected={isActive}\n className={cn(\n styles.option,\n isActive && styles.active,\n )}\n onMouseMove={() => setActiveIndex(index)}\n onClick={() => selectItem(item)}\n >\n {item.icon && (\n <span className={styles.icon}>{item.icon}</span>\n )}\n <span className={styles.label}>{item.label}</span>\n </li>\n );\n })}\n </ul>\n </li>\n ))\n )}\n </ul>\n </div>\n </div>,\n document.body,\n );\n}\n\nfunction SearchIcon() {\n return (\n <svg\n className={styles.searchIcon}\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M20 20l-3.5-3.5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmDialog.cjs","names":[],"sources":["../../../src/components/ConfirmDialog/ConfirmDialog.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a confirmation is a question (title, description),\n * two buttons whose copy the app must own (confirmLabel, cancelLabel), a\n * destructive-or-not tone (variant), and the async state of the answer (loading,\n * onConfirm, onCancel, open). Fewer props means the app writes the dialog again\n * around a Modal.\n */\nimport type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { Modal } from \"@/components/Modal\";\n\nexport interface ConfirmDialogProps {\n open: boolean;\n title: ReactNode;\n description?: ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: \"primary\" | \"danger\";\n loading?: boolean;\n onConfirm: () => void | Promise<void>;\n onCancel: () => void;\n}\n\n/**\n * Quick confirmation prompt built on top of {@link Modal}. Use for destructive\n * actions with `variant=\"danger\"`.\n */\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n variant = \"primary\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <Modal\n open={open}\n onClose={onCancel}\n title={title}\n size=\"sm\"\n footer={\n <>\n <Button variant=\"secondary\" onClick={onCancel} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button variant={variant} loading={loading} onClick={() => void onConfirm()}>\n {confirmLabel}\n </Button>\n </>\n }\n >\n {description}\n </Modal>\n );\n}\n"],"mappings":"2GA2BA,SAAgB,EAAc,CAC1B,OACA,QACA,cACA,eAAe,YACf,cAAc,WACd,UAAU,UACV,UAAU,GACV,YACA,YACmB,CACnB,OACI,EAAA,EAAA,IAAA,CAAC,EAAA,MAAD,CACU,OACN,QAAS,EACF,QACP,KAAK,KACL,QACI,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CAAQ,QAAQ,YAAY,QAAS,EAAU,SAAU,WACpD,CACG,CAAA,GACR,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CAAiB,UAAkB,UAAS,YAAe,KAAK,EAAU,WACrE,CACG,CAAA,CACV,CAAA,CAAA,WAGL,CACE,CAAA,CAEf"}
1
+ {"version":3,"file":"ConfirmDialog.cjs","names":[],"sources":["../../../src/components/ConfirmDialog/ConfirmDialog.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a confirmation is a question (title, description),\n * two buttons whose copy the app must own (confirmLabel, cancelLabel), a\n * destructive-or-not tone (variant), and the async state of the answer (loading,\n * onConfirm, onCancel, open). Fewer props means the app writes the dialog again\n * around a Modal.\n */\nimport type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { Modal } from \"@/components/Modal\";\n\nexport interface ConfirmDialogProps {\n open: boolean;\n title: ReactNode;\n description?: ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: \"primary\" | \"danger\";\n loading?: boolean;\n onConfirm: () => void | Promise<void>;\n onCancel: () => void;\n}\n\n/**\n * Quick confirmation prompt built on top of {@link Modal}. Use for destructive\n * actions with `variant=\"danger\"`.\n */\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n variant = \"primary\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <Modal\n open={open}\n onClose={onCancel}\n title={title}\n size=\"sm\"\n footer={\n <>\n <Button variant=\"secondary\" onClick={onCancel} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button variant={variant} loading={loading} onClick={() => void onConfirm()}>\n {confirmLabel}\n </Button>\n </>\n }\n >\n {description}\n </Modal>\n );\n}\n"],"mappings":"2GA2BA,SAAgB,EAAc,CAC1B,OACA,QACA,cACA,eAAe,YACf,cAAc,WACd,UAAU,UACV,UAAU,GACV,YACA,YACmB,CACnB,OACI,EAAA,EAAA,IAAA,CAAC,EAAA,MAAD,CACU,OACN,QAAS,EACF,QACP,KAAK,KACL,QACI,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CAAQ,QAAQ,YAAY,QAAS,EAAU,SAAU,EACpD,SAAA,CACG,CAAA,GACR,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CAAiB,UAAkB,UAAS,YAAe,KAAK,EAAU,EACrE,SAAA,CACG,CAAA,CACV,CAAA,CAAA,EAGL,SAAA,CACE,CAAA,CAEf"}
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmDialog.js","names":[],"sources":["../../../src/components/ConfirmDialog/ConfirmDialog.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a confirmation is a question (title, description),\n * two buttons whose copy the app must own (confirmLabel, cancelLabel), a\n * destructive-or-not tone (variant), and the async state of the answer (loading,\n * onConfirm, onCancel, open). Fewer props means the app writes the dialog again\n * around a Modal.\n */\nimport type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { Modal } from \"@/components/Modal\";\n\nexport interface ConfirmDialogProps {\n open: boolean;\n title: ReactNode;\n description?: ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: \"primary\" | \"danger\";\n loading?: boolean;\n onConfirm: () => void | Promise<void>;\n onCancel: () => void;\n}\n\n/**\n * Quick confirmation prompt built on top of {@link Modal}. Use for destructive\n * actions with `variant=\"danger\"`.\n */\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n variant = \"primary\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <Modal\n open={open}\n onClose={onCancel}\n title={title}\n size=\"sm\"\n footer={\n <>\n <Button variant=\"secondary\" onClick={onCancel} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button variant={variant} loading={loading} onClick={() => void onConfirm()}>\n {confirmLabel}\n </Button>\n </>\n }\n >\n {description}\n </Modal>\n );\n}\n"],"mappings":";;;;AA2BA,SAAgB,EAAc,EAC1B,SACA,UACA,gBACA,kBAAe,aACf,iBAAc,YACd,aAAU,WACV,aAAU,IACV,cACA,eACmB;CACnB,OACI,kBAAC,GAAD;EACU;EACN,SAAS;EACF;EACP,MAAK;EACL,QACI,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,GAAD;GAAQ,SAAQ;GAAY,SAAS;GAAU,UAAU;aACpD;EACG,CAAA,GACR,kBAAC,GAAD;GAAiB;GAAkB;GAAS,eAAe,KAAK,EAAU;aACrE;EACG,CAAA,CACV,EAAA,CAAA;YAGL;CACE,CAAA;AAEf"}
1
+ {"version":3,"file":"ConfirmDialog.js","names":[],"sources":["../../../src/components/ConfirmDialog/ConfirmDialog.tsx"],"sourcesContent":["/**\n * @tempest-limits props-count — a confirmation is a question (title, description),\n * two buttons whose copy the app must own (confirmLabel, cancelLabel), a\n * destructive-or-not tone (variant), and the async state of the answer (loading,\n * onConfirm, onCancel, open). Fewer props means the app writes the dialog again\n * around a Modal.\n */\nimport type { ReactNode } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { Modal } from \"@/components/Modal\";\n\nexport interface ConfirmDialogProps {\n open: boolean;\n title: ReactNode;\n description?: ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: \"primary\" | \"danger\";\n loading?: boolean;\n onConfirm: () => void | Promise<void>;\n onCancel: () => void;\n}\n\n/**\n * Quick confirmation prompt built on top of {@link Modal}. Use for destructive\n * actions with `variant=\"danger\"`.\n */\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n variant = \"primary\",\n loading = false,\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n return (\n <Modal\n open={open}\n onClose={onCancel}\n title={title}\n size=\"sm\"\n footer={\n <>\n <Button variant=\"secondary\" onClick={onCancel} disabled={loading}>\n {cancelLabel}\n </Button>\n <Button variant={variant} loading={loading} onClick={() => void onConfirm()}>\n {confirmLabel}\n </Button>\n </>\n }\n >\n {description}\n </Modal>\n );\n}\n"],"mappings":";;;;AA2BA,SAAgB,EAAc,EAC1B,SACA,UACA,gBACA,kBAAe,aACf,iBAAc,YACd,aAAU,WACV,aAAU,IACV,cACA,eACmB;CACnB,OACI,kBAAC,GAAD;EACU;EACN,SAAS;EACF;EACP,MAAK;EACL,QACI,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,GAAD;GAAQ,SAAQ;GAAY,SAAS;GAAU,UAAU;GACpD,UAAA;EACG,CAAA,GACR,kBAAC,GAAD;GAAiB;GAAkB;GAAS,eAAe,KAAK,EAAU;GACrE,UAAA;EACG,CAAA,CACV,EAAA,CAAA;EAGL,UAAA;CACE,CAAA;AAEf"}
@@ -1 +1 @@
1
- {"version":3,"file":"ContextMenu.cjs","names":[],"sources":["../../../src/components/ContextMenu/ContextMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body positions the menu against the pointer,\n * flips it inside the viewport, and owns roving focus for the keyboard path — one\n * geometry computed from one anchor point.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Portal } from \"@/components/Portal\";\nimport styles from \"./ContextMenu.module.css\";\n\nexport type ContextMenuItem =\n | {\n label: ReactNode;\n onSelect?: () => void;\n disabled?: boolean;\n danger?: boolean;\n }\n | { separator: true };\n\nexport interface ContextMenuProps {\n /** Menu entries — selectable items and separators. */\n items: ContextMenuItem[];\n /** Trigger area. Right-clicking anywhere within opens the menu at the cursor. */\n children: ReactNode;\n /** Extra class names forwarded to the menu element. */\n className?: string;\n}\n\ninterface Position {\n x: number;\n y: number;\n}\n\nfunction isSeparator(item: ContextMenuItem): item is { separator: true } {\n return \"separator\" in item && item.separator === true;\n}\n\n/**\n * Right-click context menu.\n *\n * - Opens at the cursor position on `onContextMenu` (default browser menu suppressed).\n * - Rendered through a {@link Portal} so it escapes parent overflow/stacking contexts.\n * - Closes on outside click, Escape, or item selection.\n * - Arrow Up/Down move focus across selectable items; Enter activates the focused item.\n *\n * @param props - The context menu props.\n * @returns The trigger wrapper plus the portalled menu when open.\n */\nexport function ContextMenu({ items, children, className }: ContextMenuProps) {\n const [open, setOpen] = useState(false);\n const [position, setPosition] = useState<Position>({ x: 0, y: 0 });\n const [activeIndex, setActiveIndex] = useState<number>(-1);\n const id = useId();\n const menuRef = useRef<HTMLUListElement>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n const selectableIndexes = items\n .map((item, index) => (!isSeparator(item) && !item.disabled ? index : -1))\n .filter((i) => i !== -1);\n\n const close = useCallback((): void => {\n setOpen(false);\n setActiveIndex(-1);\n }, []);\n\n const handleContextMenu = (event: React.MouseEvent): void => {\n event.preventDefault();\n setPosition({ x: event.clientX, y: event.clientY });\n setActiveIndex(-1);\n setOpen(true);\n };\n\n useEffect(() => {\n if (!open) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n close();\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const next = selectableIndexes[(current + 1) % selectableIndexes.length] ?? -1;\n setActiveIndex(next);\n itemRefs.current[next]?.focus();\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const prev =\n selectableIndexes[\n (current - 1 + selectableIndexes.length) % selectableIndexes.length\n ] ?? -1;\n setActiveIndex(prev);\n itemRefs.current[prev]?.focus();\n }\n };\n const onDown = (event: MouseEvent): void => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [open, activeIndex, selectableIndexes, close]);\n\n const handleSelect = (item: Extract<ContextMenuItem, { label: ReactNode }>): void => {\n item.onSelect?.();\n close();\n };\n\n return (\n <>\n <span className={styles.root} onContextMenu={handleContextMenu}>\n {children}\n </span>\n {open && (\n <Portal>\n <ul\n ref={menuRef}\n id={id}\n role=\"menu\"\n className={cn(styles.menu, className)}\n style={{ top: position.y, left: position.x }}\n >\n {items.map((item, index) => {\n if (isSeparator(item)) {\n return (\n <li\n key={`separator-${index}`}\n role=\"separator\"\n className={styles.separator}\n aria-hidden\n />\n );\n }\n return (\n <li key={`item-${index}`} role=\"none\">\n <button\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n type=\"button\"\n role=\"menuitem\"\n className={cn(\n styles.item,\n item.danger && styles.danger,\n activeIndex === index && styles.active,\n )}\n disabled={item.disabled}\n onClick={() => handleSelect(item)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {item.label}\n </button>\n </li>\n );\n })}\n </ul>\n </Portal>\n )}\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ContextMenu.cjs","names":[],"sources":["../../../src/components/ContextMenu/ContextMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body positions the menu against the pointer,\n * flips it inside the viewport, and owns roving focus for the keyboard path — one\n * geometry computed from one anchor point.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Portal } from \"@/components/Portal\";\nimport styles from \"./ContextMenu.module.css\";\n\nexport type ContextMenuItem =\n | {\n label: ReactNode;\n onSelect?: () => void;\n disabled?: boolean;\n danger?: boolean;\n }\n | { separator: true };\n\nexport interface ContextMenuProps {\n /** Menu entries — selectable items and separators. */\n items: ContextMenuItem[];\n /** Trigger area. Right-clicking anywhere within opens the menu at the cursor. */\n children: ReactNode;\n /** Extra class names forwarded to the menu element. */\n className?: string;\n}\n\ninterface Position {\n x: number;\n y: number;\n}\n\nfunction isSeparator(item: ContextMenuItem): item is { separator: true } {\n return \"separator\" in item && item.separator === true;\n}\n\n/**\n * Right-click context menu.\n *\n * - Opens at the cursor position on `onContextMenu` (default browser menu suppressed).\n * - Rendered through a {@link Portal} so it escapes parent overflow/stacking contexts.\n * - Closes on outside click, Escape, or item selection.\n * - Arrow Up/Down move focus across selectable items; Enter activates the focused item.\n *\n * @param props - The context menu props.\n * @returns The trigger wrapper plus the portalled menu when open.\n */\nexport function ContextMenu({ items, children, className }: ContextMenuProps) {\n const [open, setOpen] = useState(false);\n const [position, setPosition] = useState<Position>({ x: 0, y: 0 });\n const [activeIndex, setActiveIndex] = useState<number>(-1);\n const id = useId();\n const menuRef = useRef<HTMLUListElement>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n const selectableIndexes = items\n .map((item, index) => (!isSeparator(item) && !item.disabled ? index : -1))\n .filter((i) => i !== -1);\n\n const close = useCallback((): void => {\n setOpen(false);\n setActiveIndex(-1);\n }, []);\n\n const handleContextMenu = (event: React.MouseEvent): void => {\n event.preventDefault();\n setPosition({ x: event.clientX, y: event.clientY });\n setActiveIndex(-1);\n setOpen(true);\n };\n\n useEffect(() => {\n if (!open) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n close();\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const next = selectableIndexes[(current + 1) % selectableIndexes.length] ?? -1;\n setActiveIndex(next);\n itemRefs.current[next]?.focus();\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const prev =\n selectableIndexes[\n (current - 1 + selectableIndexes.length) % selectableIndexes.length\n ] ?? -1;\n setActiveIndex(prev);\n itemRefs.current[prev]?.focus();\n }\n };\n const onDown = (event: MouseEvent): void => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [open, activeIndex, selectableIndexes, close]);\n\n const handleSelect = (item: Extract<ContextMenuItem, { label: ReactNode }>): void => {\n item.onSelect?.();\n close();\n };\n\n return (\n <>\n <span className={styles.root} onContextMenu={handleContextMenu}>\n {children}\n </span>\n {open && (\n <Portal>\n <ul\n ref={menuRef}\n id={id}\n role=\"menu\"\n className={cn(styles.menu, className)}\n style={{ top: position.y, left: position.x }}\n >\n {items.map((item, index) => {\n if (isSeparator(item)) {\n return (\n <li\n key={`separator-${index}`}\n role=\"separator\"\n className={styles.separator}\n aria-hidden\n />\n );\n }\n return (\n <li key={`item-${index}`} role=\"none\">\n <button\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n type=\"button\"\n role=\"menuitem\"\n className={cn(\n styles.item,\n item.danger && styles.danger,\n activeIndex === index && styles.active,\n )}\n disabled={item.disabled}\n onClick={() => handleSelect(item)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {item.label}\n </button>\n </li>\n );\n })}\n </ul>\n </Portal>\n )}\n </>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ContextMenu.js","names":[],"sources":["../../../src/components/ContextMenu/ContextMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body positions the menu against the pointer,\n * flips it inside the viewport, and owns roving focus for the keyboard path — one\n * geometry computed from one anchor point.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Portal } from \"@/components/Portal\";\nimport styles from \"./ContextMenu.module.css\";\n\nexport type ContextMenuItem =\n | {\n label: ReactNode;\n onSelect?: () => void;\n disabled?: boolean;\n danger?: boolean;\n }\n | { separator: true };\n\nexport interface ContextMenuProps {\n /** Menu entries — selectable items and separators. */\n items: ContextMenuItem[];\n /** Trigger area. Right-clicking anywhere within opens the menu at the cursor. */\n children: ReactNode;\n /** Extra class names forwarded to the menu element. */\n className?: string;\n}\n\ninterface Position {\n x: number;\n y: number;\n}\n\nfunction isSeparator(item: ContextMenuItem): item is { separator: true } {\n return \"separator\" in item && item.separator === true;\n}\n\n/**\n * Right-click context menu.\n *\n * - Opens at the cursor position on `onContextMenu` (default browser menu suppressed).\n * - Rendered through a {@link Portal} so it escapes parent overflow/stacking contexts.\n * - Closes on outside click, Escape, or item selection.\n * - Arrow Up/Down move focus across selectable items; Enter activates the focused item.\n *\n * @param props - The context menu props.\n * @returns The trigger wrapper plus the portalled menu when open.\n */\nexport function ContextMenu({ items, children, className }: ContextMenuProps) {\n const [open, setOpen] = useState(false);\n const [position, setPosition] = useState<Position>({ x: 0, y: 0 });\n const [activeIndex, setActiveIndex] = useState<number>(-1);\n const id = useId();\n const menuRef = useRef<HTMLUListElement>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n const selectableIndexes = items\n .map((item, index) => (!isSeparator(item) && !item.disabled ? index : -1))\n .filter((i) => i !== -1);\n\n const close = useCallback((): void => {\n setOpen(false);\n setActiveIndex(-1);\n }, []);\n\n const handleContextMenu = (event: React.MouseEvent): void => {\n event.preventDefault();\n setPosition({ x: event.clientX, y: event.clientY });\n setActiveIndex(-1);\n setOpen(true);\n };\n\n useEffect(() => {\n if (!open) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n close();\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const next = selectableIndexes[(current + 1) % selectableIndexes.length] ?? -1;\n setActiveIndex(next);\n itemRefs.current[next]?.focus();\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const prev =\n selectableIndexes[\n (current - 1 + selectableIndexes.length) % selectableIndexes.length\n ] ?? -1;\n setActiveIndex(prev);\n itemRefs.current[prev]?.focus();\n }\n };\n const onDown = (event: MouseEvent): void => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [open, activeIndex, selectableIndexes, close]);\n\n const handleSelect = (item: Extract<ContextMenuItem, { label: ReactNode }>): void => {\n item.onSelect?.();\n close();\n };\n\n return (\n <>\n <span className={styles.root} onContextMenu={handleContextMenu}>\n {children}\n </span>\n {open && (\n <Portal>\n <ul\n ref={menuRef}\n id={id}\n role=\"menu\"\n className={cn(styles.menu, className)}\n style={{ top: position.y, left: position.x }}\n >\n {items.map((item, index) => {\n if (isSeparator(item)) {\n return (\n <li\n key={`separator-${index}`}\n role=\"separator\"\n className={styles.separator}\n aria-hidden\n />\n );\n }\n return (\n <li key={`item-${index}`} role=\"none\">\n <button\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n type=\"button\"\n role=\"menuitem\"\n className={cn(\n styles.item,\n item.danger && styles.danger,\n activeIndex === index && styles.active,\n )}\n disabled={item.disabled}\n onClick={() => handleSelect(item)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {item.label}\n </button>\n </li>\n );\n })}\n </ul>\n </Portal>\n )}\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ContextMenu.js","names":[],"sources":["../../../src/components/ContextMenu/ContextMenu.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body positions the menu against the pointer,\n * flips it inside the viewport, and owns roving focus for the keyboard path — one\n * geometry computed from one anchor point.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Portal } from \"@/components/Portal\";\nimport styles from \"./ContextMenu.module.css\";\n\nexport type ContextMenuItem =\n | {\n label: ReactNode;\n onSelect?: () => void;\n disabled?: boolean;\n danger?: boolean;\n }\n | { separator: true };\n\nexport interface ContextMenuProps {\n /** Menu entries — selectable items and separators. */\n items: ContextMenuItem[];\n /** Trigger area. Right-clicking anywhere within opens the menu at the cursor. */\n children: ReactNode;\n /** Extra class names forwarded to the menu element. */\n className?: string;\n}\n\ninterface Position {\n x: number;\n y: number;\n}\n\nfunction isSeparator(item: ContextMenuItem): item is { separator: true } {\n return \"separator\" in item && item.separator === true;\n}\n\n/**\n * Right-click context menu.\n *\n * - Opens at the cursor position on `onContextMenu` (default browser menu suppressed).\n * - Rendered through a {@link Portal} so it escapes parent overflow/stacking contexts.\n * - Closes on outside click, Escape, or item selection.\n * - Arrow Up/Down move focus across selectable items; Enter activates the focused item.\n *\n * @param props - The context menu props.\n * @returns The trigger wrapper plus the portalled menu when open.\n */\nexport function ContextMenu({ items, children, className }: ContextMenuProps) {\n const [open, setOpen] = useState(false);\n const [position, setPosition] = useState<Position>({ x: 0, y: 0 });\n const [activeIndex, setActiveIndex] = useState<number>(-1);\n const id = useId();\n const menuRef = useRef<HTMLUListElement>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n const selectableIndexes = items\n .map((item, index) => (!isSeparator(item) && !item.disabled ? index : -1))\n .filter((i) => i !== -1);\n\n const close = useCallback((): void => {\n setOpen(false);\n setActiveIndex(-1);\n }, []);\n\n const handleContextMenu = (event: React.MouseEvent): void => {\n event.preventDefault();\n setPosition({ x: event.clientX, y: event.clientY });\n setActiveIndex(-1);\n setOpen(true);\n };\n\n useEffect(() => {\n if (!open) return;\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n close();\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const next = selectableIndexes[(current + 1) % selectableIndexes.length] ?? -1;\n setActiveIndex(next);\n itemRefs.current[next]?.focus();\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n const current = selectableIndexes.indexOf(activeIndex);\n const prev =\n selectableIndexes[\n (current - 1 + selectableIndexes.length) % selectableIndexes.length\n ] ?? -1;\n setActiveIndex(prev);\n itemRefs.current[prev]?.focus();\n }\n };\n const onDown = (event: MouseEvent): void => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) close();\n };\n window.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"mousedown\", onDown);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"mousedown\", onDown);\n };\n }, [open, activeIndex, selectableIndexes, close]);\n\n const handleSelect = (item: Extract<ContextMenuItem, { label: ReactNode }>): void => {\n item.onSelect?.();\n close();\n };\n\n return (\n <>\n <span className={styles.root} onContextMenu={handleContextMenu}>\n {children}\n </span>\n {open && (\n <Portal>\n <ul\n ref={menuRef}\n id={id}\n role=\"menu\"\n className={cn(styles.menu, className)}\n style={{ top: position.y, left: position.x }}\n >\n {items.map((item, index) => {\n if (isSeparator(item)) {\n return (\n <li\n key={`separator-${index}`}\n role=\"separator\"\n className={styles.separator}\n aria-hidden\n />\n );\n }\n return (\n <li key={`item-${index}`} role=\"none\">\n <button\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n type=\"button\"\n role=\"menuitem\"\n className={cn(\n styles.item,\n item.danger && styles.danger,\n activeIndex === index && styles.active,\n )}\n disabled={item.disabled}\n onClick={() => handleSelect(item)}\n onMouseEnter={() => setActiveIndex(index)}\n >\n {item.label}\n </button>\n </li>\n );\n })}\n </ul>\n </Portal>\n )}\n </>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CopyButton.cjs","names":[],"sources":["../../../src/components/CopyButton/CopyButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./CopyButton.module.css\";\n\nexport interface CopyButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Text written to the clipboard when the button is clicked. */\n value: string;\n /** How long (ms) the \"copied\" state stays active before resetting. Defaults to 2000. */\n timeout?: number;\n /** Optional label. Falls back to \"Copy\" / \"Copied\" based on state. */\n children?: ReactNode;\n /** Called after a successful clipboard write. */\n onCopied?: () => void;\n}\n\n/**\n * Button that copies a string to the clipboard and shows a transient \"copied\"\n * state for `timeout` milliseconds.\n *\n * When `children` are provided they are rendered in both states; otherwise the\n * label toggles between \"Copy\" and \"Copied\". The reset timer is cleared on\n * unmount to avoid setting state on an unmounted component.\n *\n * @tempest-limits empty-catch — `navigator.clipboard.writeText` rejects when the\n * page is not a secure context, when the document is not focused, or when the user\n * denied the permission. None of those are recoverable here and none deserve an\n * error surface: the button simply never enters the \"copied\" state, which is the\n * feedback the user needs.\n *\n * @example\n * <CopyButton value=\"npm i tempest-react-sdk\" />\n */\nexport function CopyButton({\n value,\n timeout = 2000,\n children,\n onCopied,\n className,\n onClick,\n ...props\n}: CopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n };\n }, []);\n\n const handleClick = useCallback(\n async (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n onCopied?.();\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setCopied(false), timeout);\n } catch {\n /* empty */\n }\n },\n [value, timeout, onCopied, onClick],\n );\n\n return (\n <button\n type=\"button\"\n className={cn(styles.button, copied && styles.copied, className)}\n data-copied={copied || undefined}\n onClick={handleClick}\n {...props}\n >\n {children ?? (copied ? \"Copied\" : \"Copy\")}\n </button>\n );\n}\n"],"mappings":"iIAiCA,SAAgB,EAAW,CACvB,QACA,UAAU,IACV,WACA,WACA,YACA,UACA,GAAG,GACa,CAChB,GAAM,CAAC,EAAQ,IAAA,EAAA,EAAA,SAAA,CAAsB,EAAK,EACpC,GAAA,EAAA,EAAA,OAAA,CAAwD,IAAI,GAElE,EAAA,EAAA,UAAA,SACiB,CACL,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,CAChE,EACD,CAAC,CAAC,EAEL,IAAM,GAAA,EAAA,EAAA,YAAA,CACF,KAAO,IAA+C,CAClD,IAAU,CAAK,EACf,GAAI,CACA,MAAM,UAAU,UAAU,UAAU,CAAK,EACzC,EAAU,EAAI,EACd,IAAW,EACP,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,EAC5D,EAAS,QAAU,eAAiB,EAAU,EAAK,EAAG,CAAO,CACjE,MAAQ,CAER,CACJ,EACA,CAAC,EAAO,EAAS,EAAU,CAAO,CACtC,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,OAAQ,GAAU,EAAA,QAAO,OAAQ,CAAS,EAC/D,cAAa,GAAU,IAAA,GACvB,QAAS,EACT,GAAI,WAEH,IAAa,EAAS,SAAW,OAC9B,CAAA,CAEhB"}
1
+ {"version":3,"file":"CopyButton.cjs","names":[],"sources":["../../../src/components/CopyButton/CopyButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./CopyButton.module.css\";\n\nexport interface CopyButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Text written to the clipboard when the button is clicked. */\n value: string;\n /** How long (ms) the \"copied\" state stays active before resetting. Defaults to 2000. */\n timeout?: number;\n /** Optional label. Falls back to \"Copy\" / \"Copied\" based on state. */\n children?: ReactNode;\n /** Called after a successful clipboard write. */\n onCopied?: () => void;\n}\n\n/**\n * Button that copies a string to the clipboard and shows a transient \"copied\"\n * state for `timeout` milliseconds.\n *\n * When `children` are provided they are rendered in both states; otherwise the\n * label toggles between \"Copy\" and \"Copied\". The reset timer is cleared on\n * unmount to avoid setting state on an unmounted component.\n *\n * @tempest-limits empty-catch — `navigator.clipboard.writeText` rejects when the\n * page is not a secure context, when the document is not focused, or when the user\n * denied the permission. None of those are recoverable here and none deserve an\n * error surface: the button simply never enters the \"copied\" state, which is the\n * feedback the user needs.\n *\n * @example\n * <CopyButton value=\"npm i tempest-react-sdk\" />\n */\nexport function CopyButton({\n value,\n timeout = 2000,\n children,\n onCopied,\n className,\n onClick,\n ...props\n}: CopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n };\n }, []);\n\n const handleClick = useCallback(\n async (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n onCopied?.();\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setCopied(false), timeout);\n } catch {\n /* empty */\n }\n },\n [value, timeout, onCopied, onClick],\n );\n\n return (\n <button\n type=\"button\"\n className={cn(styles.button, copied && styles.copied, className)}\n data-copied={copied || undefined}\n onClick={handleClick}\n {...props}\n >\n {children ?? (copied ? \"Copied\" : \"Copy\")}\n </button>\n );\n}\n"],"mappings":"iIAiCA,SAAgB,EAAW,CACvB,QACA,UAAU,IACV,WACA,WACA,YACA,UACA,GAAG,GACa,CAChB,GAAM,CAAC,EAAQ,IAAA,EAAa,EAAA,SAAA,CAAS,EAAK,EACpC,GAAA,EAAW,EAAA,OAAA,CAA6C,IAAI,GAElE,EAAA,EAAA,UAAA,SACiB,CACL,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,CAChE,EACD,CAAC,CAAC,EAEL,IAAM,GAAA,EAAc,EAAA,YAAA,CAChB,KAAO,IAA+C,CAClD,IAAU,CAAK,EACf,GAAI,CACA,MAAM,UAAU,UAAU,UAAU,CAAK,EACzC,EAAU,EAAI,EACd,IAAW,EACP,EAAS,UAAY,MAAM,aAAa,EAAS,OAAO,EAC5D,EAAS,QAAU,eAAiB,EAAU,EAAK,EAAG,CAAO,CACjE,MAAQ,CAER,CACJ,EACA,CAAC,EAAO,EAAS,EAAU,CAAO,CACtC,EAEA,OACI,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,OAAQ,GAAU,EAAA,QAAO,OAAQ,CAAS,EAC/D,cAAa,GAAU,IAAA,GACvB,QAAS,EACT,GAAI,EAEH,SAAA,IAAa,EAAS,SAAW,OAC9B,CAAA,CAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"CopyButton.js","names":[],"sources":["../../../src/components/CopyButton/CopyButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./CopyButton.module.css\";\n\nexport interface CopyButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Text written to the clipboard when the button is clicked. */\n value: string;\n /** How long (ms) the \"copied\" state stays active before resetting. Defaults to 2000. */\n timeout?: number;\n /** Optional label. Falls back to \"Copy\" / \"Copied\" based on state. */\n children?: ReactNode;\n /** Called after a successful clipboard write. */\n onCopied?: () => void;\n}\n\n/**\n * Button that copies a string to the clipboard and shows a transient \"copied\"\n * state for `timeout` milliseconds.\n *\n * When `children` are provided they are rendered in both states; otherwise the\n * label toggles between \"Copy\" and \"Copied\". The reset timer is cleared on\n * unmount to avoid setting state on an unmounted component.\n *\n * @tempest-limits empty-catch — `navigator.clipboard.writeText` rejects when the\n * page is not a secure context, when the document is not focused, or when the user\n * denied the permission. None of those are recoverable here and none deserve an\n * error surface: the button simply never enters the \"copied\" state, which is the\n * feedback the user needs.\n *\n * @example\n * <CopyButton value=\"npm i tempest-react-sdk\" />\n */\nexport function CopyButton({\n value,\n timeout = 2000,\n children,\n onCopied,\n className,\n onClick,\n ...props\n}: CopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n };\n }, []);\n\n const handleClick = useCallback(\n async (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n onCopied?.();\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setCopied(false), timeout);\n } catch {\n /* empty */\n }\n },\n [value, timeout, onCopied, onClick],\n );\n\n return (\n <button\n type=\"button\"\n className={cn(styles.button, copied && styles.copied, className)}\n data-copied={copied || undefined}\n onClick={handleClick}\n {...props}\n >\n {children ?? (copied ? \"Copied\" : \"Copy\")}\n </button>\n );\n}\n"],"mappings":";;;;;AAiCA,SAAgB,EAAW,EACvB,UACA,aAAU,KACV,aACA,aACA,cACA,YACA,GAAG,KACa;CAChB,IAAM,CAAC,GAAQ,KAAa,EAAS,EAAK,GACpC,IAAW,EAA6C,IAAI;CAElE,cACiB;EACT,AAAI,EAAS,YAAY,QAAM,aAAa,EAAS,OAAO;CAChE,GACD,CAAC,CAAC;CAEL,IAAM,IAAc,EAChB,OAAO,MAA+C;EAClD,IAAU,CAAK;EACf,IAAI;GAKA,AAJA,MAAM,UAAU,UAAU,UAAU,CAAK,GACzC,EAAU,EAAI,GACd,IAAW,GACP,EAAS,YAAY,QAAM,aAAa,EAAS,OAAO,GAC5D,EAAS,UAAU,iBAAiB,EAAU,EAAK,GAAG,CAAO;EACjE,QAAQ,CAER;CACJ,GACA;EAAC;EAAO;EAAS;EAAU;CAAO,CACtC;CAEA,OACI,kBAAC,UAAD;EACI,MAAK;EACL,WAAW,EAAG,EAAO,QAAQ,KAAU,EAAO,QAAQ,CAAS;EAC/D,eAAa,KAAU,KAAA;EACvB,SAAS;EACT,GAAI;YAEH,MAAa,IAAS,WAAW;CAC9B,CAAA;AAEhB"}
1
+ {"version":3,"file":"CopyButton.js","names":[],"sources":["../../../src/components/CopyButton/CopyButton.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./CopyButton.module.css\";\n\nexport interface CopyButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Text written to the clipboard when the button is clicked. */\n value: string;\n /** How long (ms) the \"copied\" state stays active before resetting. Defaults to 2000. */\n timeout?: number;\n /** Optional label. Falls back to \"Copy\" / \"Copied\" based on state. */\n children?: ReactNode;\n /** Called after a successful clipboard write. */\n onCopied?: () => void;\n}\n\n/**\n * Button that copies a string to the clipboard and shows a transient \"copied\"\n * state for `timeout` milliseconds.\n *\n * When `children` are provided they are rendered in both states; otherwise the\n * label toggles between \"Copy\" and \"Copied\". The reset timer is cleared on\n * unmount to avoid setting state on an unmounted component.\n *\n * @tempest-limits empty-catch — `navigator.clipboard.writeText` rejects when the\n * page is not a secure context, when the document is not focused, or when the user\n * denied the permission. None of those are recoverable here and none deserve an\n * error surface: the button simply never enters the \"copied\" state, which is the\n * feedback the user needs.\n *\n * @example\n * <CopyButton value=\"npm i tempest-react-sdk\" />\n */\nexport function CopyButton({\n value,\n timeout = 2000,\n children,\n onCopied,\n className,\n onClick,\n ...props\n}: CopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n };\n }, []);\n\n const handleClick = useCallback(\n async (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n onCopied?.();\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setCopied(false), timeout);\n } catch {\n /* empty */\n }\n },\n [value, timeout, onCopied, onClick],\n );\n\n return (\n <button\n type=\"button\"\n className={cn(styles.button, copied && styles.copied, className)}\n data-copied={copied || undefined}\n onClick={handleClick}\n {...props}\n >\n {children ?? (copied ? \"Copied\" : \"Copy\")}\n </button>\n );\n}\n"],"mappings":";;;;;AAiCA,SAAgB,EAAW,EACvB,UACA,aAAU,KACV,aACA,aACA,cACA,YACA,GAAG,KACa;CAChB,IAAM,CAAC,GAAQ,KAAa,EAAS,EAAK,GACpC,IAAW,EAA6C,IAAI;CAElE,cACiB;EACT,AAAI,EAAS,YAAY,QAAM,aAAa,EAAS,OAAO;CAChE,GACD,CAAC,CAAC;CAEL,IAAM,IAAc,EAChB,OAAO,MAA+C;EAClD,IAAU,CAAK;EACf,IAAI;GAKA,AAJA,MAAM,UAAU,UAAU,UAAU,CAAK,GACzC,EAAU,EAAI,GACd,IAAW,GACP,EAAS,YAAY,QAAM,aAAa,EAAS,OAAO,GAC5D,EAAS,UAAU,iBAAiB,EAAU,EAAK,GAAG,CAAO;EACjE,QAAQ,CAER;CACJ,GACA;EAAC;EAAO;EAAS;EAAU;CAAO,CACtC;CAEA,OACI,kBAAC,UAAD;EACI,MAAK;EACL,WAAW,EAAG,EAAO,QAAQ,KAAU,EAAO,QAAQ,CAAS;EAC/D,eAAa,KAAU,KAAA;EACvB,SAAS;EACT,GAAI;EAEH,UAAA,MAAa,IAAS,WAAW;CAC9B,CAAA;AAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"DataList.cjs","names":[],"sources":["../../../src/components/DataList/DataList.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./DataList.module.css\";\n\nexport interface DataListProps<T> extends HTMLAttributes<HTMLUListElement> {\n /** The collection to render, one `<li>` per item. */\n items: readonly T[];\n /** Renders the contents of each list item. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Derives a stable React key for each item (defaults to the index). */\n keyExtractor?: (item: T, index: number) => string | number;\n /** Node rendered in place of the list when `items` is empty. */\n empty?: ReactNode;\n}\n\n/**\n * Generic, typed list that renders a `<ul>` with one `<li>` per item.\n *\n * The component is generic over the item type so `renderItem` and\n * `keyExtractor` infer their argument types from `items`. When `items` is\n * empty it renders `empty` (or nothing) instead of an empty list.\n *\n * @param items - The collection to render.\n * @param renderItem - Renders the contents of each list item.\n * @param keyExtractor - Optional stable key derivation (defaults to index).\n * @param empty - Optional node shown when there are no items.\n * @returns The rendered list, or the `empty` node when there are no items.\n */\nexport function DataList<T>({\n items,\n renderItem,\n keyExtractor,\n empty,\n className,\n ...props\n}: DataListProps<T>) {\n if (items.length === 0) {\n return <>{empty ?? null}</>;\n }\n\n return (\n <ul className={cn(styles.list, className)} {...props}>\n {items.map((item, index) => (\n <li key={keyExtractor ? keyExtractor(item, index) : index} className={styles.item}>\n {renderItem(item, index)}\n </li>\n ))}\n </ul>\n );\n}\n"],"mappings":"4GA4BA,SAAgB,EAAY,CACxB,QACA,aACA,eACA,QACA,YACA,GAAG,GACc,CAKjB,OAJI,EAAM,SAAW,GACV,EAAA,EAAA,IAAA,CAAA,EAAA,SAAA,CAAA,SAAG,GAAS,IAAO,CAAA,GAI1B,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EAAG,GAAI,WAC1C,EAAM,KAAK,EAAM,KACd,EAAA,EAAA,IAAA,CAAC,KAAD,CAA2D,UAAW,EAAA,QAAO,cACxE,EAAW,EAAM,CAAK,CACvB,EAFK,EAAe,EAAa,EAAM,CAAK,EAAI,CAEhD,CACP,CACD,CAAA,CAEZ"}
1
+ {"version":3,"file":"DataList.cjs","names":[],"sources":["../../../src/components/DataList/DataList.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./DataList.module.css\";\n\nexport interface DataListProps<T> extends HTMLAttributes<HTMLUListElement> {\n /** The collection to render, one `<li>` per item. */\n items: readonly T[];\n /** Renders the contents of each list item. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Derives a stable React key for each item (defaults to the index). */\n keyExtractor?: (item: T, index: number) => string | number;\n /** Node rendered in place of the list when `items` is empty. */\n empty?: ReactNode;\n}\n\n/**\n * Generic, typed list that renders a `<ul>` with one `<li>` per item.\n *\n * The component is generic over the item type so `renderItem` and\n * `keyExtractor` infer their argument types from `items`. When `items` is\n * empty it renders `empty` (or nothing) instead of an empty list.\n *\n * @param items - The collection to render.\n * @param renderItem - Renders the contents of each list item.\n * @param keyExtractor - Optional stable key derivation (defaults to index).\n * @param empty - Optional node shown when there are no items.\n * @returns The rendered list, or the `empty` node when there are no items.\n */\nexport function DataList<T>({\n items,\n renderItem,\n keyExtractor,\n empty,\n className,\n ...props\n}: DataListProps<T>) {\n if (items.length === 0) {\n return <>{empty ?? null}</>;\n }\n\n return (\n <ul className={cn(styles.list, className)} {...props}>\n {items.map((item, index) => (\n <li key={keyExtractor ? keyExtractor(item, index) : index} className={styles.item}>\n {renderItem(item, index)}\n </li>\n ))}\n </ul>\n );\n}\n"],"mappings":"4GA4BA,SAAgB,EAAY,CACxB,QACA,aACA,eACA,QACA,YACA,GAAG,GACc,CAKjB,OAJI,EAAM,SAAW,GACV,EAAA,EAAA,IAAA,CAAA,EAAA,SAAA,CAAA,SAAG,GAAS,IAAO,CAAA,GAI1B,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EAAG,GAAI,EAC1C,SAAA,EAAM,KAAK,EAAM,KACd,EAAA,EAAA,IAAA,CAAC,KAAD,CAA2D,UAAW,EAAA,QAAO,KACxE,SAAA,EAAW,EAAM,CAAK,CACvB,EAFK,EAAe,EAAa,EAAM,CAAK,EAAI,CAEhD,CACP,CACD,CAAA,CAEZ"}
@@ -1 +1 @@
1
- {"version":3,"file":"DataList.js","names":[],"sources":["../../../src/components/DataList/DataList.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./DataList.module.css\";\n\nexport interface DataListProps<T> extends HTMLAttributes<HTMLUListElement> {\n /** The collection to render, one `<li>` per item. */\n items: readonly T[];\n /** Renders the contents of each list item. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Derives a stable React key for each item (defaults to the index). */\n keyExtractor?: (item: T, index: number) => string | number;\n /** Node rendered in place of the list when `items` is empty. */\n empty?: ReactNode;\n}\n\n/**\n * Generic, typed list that renders a `<ul>` with one `<li>` per item.\n *\n * The component is generic over the item type so `renderItem` and\n * `keyExtractor` infer their argument types from `items`. When `items` is\n * empty it renders `empty` (or nothing) instead of an empty list.\n *\n * @param items - The collection to render.\n * @param renderItem - Renders the contents of each list item.\n * @param keyExtractor - Optional stable key derivation (defaults to index).\n * @param empty - Optional node shown when there are no items.\n * @returns The rendered list, or the `empty` node when there are no items.\n */\nexport function DataList<T>({\n items,\n renderItem,\n keyExtractor,\n empty,\n className,\n ...props\n}: DataListProps<T>) {\n if (items.length === 0) {\n return <>{empty ?? null}</>;\n }\n\n return (\n <ul className={cn(styles.list, className)} {...props}>\n {items.map((item, index) => (\n <li key={keyExtractor ? keyExtractor(item, index) : index} className={styles.item}>\n {renderItem(item, index)}\n </li>\n ))}\n </ul>\n );\n}\n"],"mappings":";;;;AA4BA,SAAgB,EAAY,EACxB,UACA,eACA,iBACA,UACA,cACA,GAAG,KACc;CAKjB,OAJI,EAAM,WAAW,IACV,kBAAA,GAAA,EAAA,UAAG,KAAS,KAAO,CAAA,IAI1B,kBAAC,MAAD;EAAI,WAAW,EAAG,EAAO,MAAM,CAAS;EAAG,GAAI;YAC1C,EAAM,KAAK,GAAM,MACd,kBAAC,MAAD;GAA2D,WAAW,EAAO;aACxE,EAAW,GAAM,CAAK;EACvB,GAFK,IAAe,EAAa,GAAM,CAAK,IAAI,CAEhD,CACP;CACD,CAAA;AAEZ"}
1
+ {"version":3,"file":"DataList.js","names":[],"sources":["../../../src/components/DataList/DataList.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./DataList.module.css\";\n\nexport interface DataListProps<T> extends HTMLAttributes<HTMLUListElement> {\n /** The collection to render, one `<li>` per item. */\n items: readonly T[];\n /** Renders the contents of each list item. */\n renderItem: (item: T, index: number) => ReactNode;\n /** Derives a stable React key for each item (defaults to the index). */\n keyExtractor?: (item: T, index: number) => string | number;\n /** Node rendered in place of the list when `items` is empty. */\n empty?: ReactNode;\n}\n\n/**\n * Generic, typed list that renders a `<ul>` with one `<li>` per item.\n *\n * The component is generic over the item type so `renderItem` and\n * `keyExtractor` infer their argument types from `items`. When `items` is\n * empty it renders `empty` (or nothing) instead of an empty list.\n *\n * @param items - The collection to render.\n * @param renderItem - Renders the contents of each list item.\n * @param keyExtractor - Optional stable key derivation (defaults to index).\n * @param empty - Optional node shown when there are no items.\n * @returns The rendered list, or the `empty` node when there are no items.\n */\nexport function DataList<T>({\n items,\n renderItem,\n keyExtractor,\n empty,\n className,\n ...props\n}: DataListProps<T>) {\n if (items.length === 0) {\n return <>{empty ?? null}</>;\n }\n\n return (\n <ul className={cn(styles.list, className)} {...props}>\n {items.map((item, index) => (\n <li key={keyExtractor ? keyExtractor(item, index) : index} className={styles.item}>\n {renderItem(item, index)}\n </li>\n ))}\n </ul>\n );\n}\n"],"mappings":";;;;AA4BA,SAAgB,EAAY,EACxB,UACA,eACA,iBACA,UACA,cACA,GAAG,KACc;CAKjB,OAJI,EAAM,WAAW,IACV,kBAAA,GAAA,EAAA,UAAG,KAAS,KAAO,CAAA,IAI1B,kBAAC,MAAD;EAAI,WAAW,EAAG,EAAO,MAAM,CAAS;EAAG,GAAI;EAC1C,UAAA,EAAM,KAAK,GAAM,MACd,kBAAC,MAAD;GAA2D,WAAW,EAAO;GACxE,UAAA,EAAW,GAAM,CAAK;EACvB,GAFK,IAAe,EAAa,GAAM,CAAK,IAAI,CAEhD,CACP;CACD,CAAA;AAEZ"}
@@ -1,2 +1,2 @@
1
- const e=require("../../utils/cn.cjs"),t=require("../../hooks/use-pagination.cjs"),n=require("../../hooks/use-announce.cjs"),r=require("../Pagination/Pagination.cjs"),i=require("../SearchBar/SearchBar.cjs"),a=require("../Table/Table.cjs"),o=require("../../utils/compare-values.cjs"),s=require("./DataTable.module.cjs"),c=require("./EditableCell.cjs"),l=require("./edit-labels.cjs");let u=require("react"),d=require("react/jsx-runtime");function f(e,t){return`${String(e)}::${String(t)}`}function p(e){return typeof e.header==`string`?e.header:String(e.key)}function m({data:m,columns:h,pageSize:g=10,searchable:_=!1,searchKeys:v,initialSort:y,rowKey:b=(e,t)=>t,emptyMessage:ee,onCellChange:x,editLabels:S,className:te,...ne}){let[C,w]=(0,u.useState)(``),[T,E]=(0,u.useState)(y??null),{page:D,setPage:O}=t.usePagination(1,g),k=n.useAnnounce(),[A,j]=(0,u.useState)(null),[M,N]=(0,u.useState)(null),[P,F]=(0,u.useState)({}),[I,L]=(0,u.useState)({}),[R,z]=(0,u.useState)({}),B=(0,u.useMemo)(()=>({...l.DEFAULT_EDIT_LABELS,...S}),[S]),V=x!==void 0&&h.some(e=>e.editable),H=(0,u.useMemo)(()=>v&&v.length>0?v:h.filter(e=>{let t=m.find(t=>t[e.key]!=null),n=t?t[e.key]:void 0;return typeof n==`string`||typeof n==`number`}).map(e=>e.key),[v,h,m]),U=(0,u.useMemo)(()=>{let e=C.trim().toLowerCase();return!e||!_?m:m.filter(t=>H.some(n=>{let r=t[n];return r!=null&&String(r).toLowerCase().includes(e)}))},[m,C,_,H]),W=(0,u.useMemo)(()=>{if(!T)return U;let e=T.direction===`asc`?1:-1;return[...U].sort((t,n)=>o.compareValues(t[T.key],n[T.key])*e)},[U,T]),G=Math.max(1,Math.ceil(W.length/g));(0,u.useEffect)(()=>{D>G&&O(G)},[D,G,O]);let K=Math.min(D,G),q=(0,u.useMemo)(()=>{let e=(K-1)*g;return W.slice(e,e+g)},[W,K,g]);function re(e){E(t=>!t||t.key!==e?{key:e,direction:`asc`}:t.direction===`asc`?{key:e,direction:`desc`}:null)}let J=(0,u.useCallback)(e=>(K-1)*g+e,[K,g]),Y=(0,u.useMemo)(()=>{if(!V)return[];let e=[];return q.forEach((t,n)=>{let r=b(t,J(n));for(let t of h)t.editable&&e.push(f(r,t.key))}),e},[V,q,h,J]),X=(0,u.useCallback)((e,t,n)=>n in P?P[n]:e[t.key],[P]),Z=(0,u.useCallback)(async(e,t,n)=>{z(t=>({...t,[e]:!0}));try{await x?.(n),k(B.saved(p(t)))}catch(n){F(t=>{let n={...t};return delete n[e],n});let r=n instanceof Error&&n.message?n.message:B.saveFailed(p(t));L(t=>({...t,[e]:r}))}finally{z(t=>{let n={...t};return delete n[e],n})}},[x,k,B]),Q=(0,u.useCallback)((e,t)=>{if(t===`none`){j(null),N(e);return}let n=Y.indexOf(e),r=Y[n+(t===`next`?1:-1)];if(r===void 0){j(null),N(e);return}j(r),N(null)},[Y]),$=(0,u.useCallback)((e,t,n,r,i,a)=>{let o=X(e,t,n);if(i===(t.formatEdit?t.formatEdit(e):String(o??``))){Q(n,a);return}let s=t.parse?t.parse(i,e):t.editorType===`number`?Number(i):i.trim(),c=t.validate?.(s,e)??null;if(c){L(e=>({...e,[n]:c}));return}L(e=>{let t={...e};return delete t[n],t}),F(e=>({...e,[n]:s})),Q(n,a),Z(n,t,{row:e,key:t.key,value:s,previous:o,rowIndex:J(r)})},[X,Q,Z,J]),ie=(0,u.useMemo)(()=>h.map(e=>{let t=T?.key===e.key?T?.direction===`asc`?` ▲`:` ▼`:``,n=e.sortable?(0,d.jsxs)(`button`,{type:`button`,className:s.default.sortButton,onClick:()=>re(e.key),"aria-label":`Ordenar por ${p(e)}`,children:[e.header,(0,d.jsx)(`span`,{className:s.default.sortIndicator,"aria-hidden":!0,children:t})]}):e.header,r=t=>e.render?e.render(t):t[e.key]??null,i=(t,n)=>{let r={...t,[e.key]:n};return e.render?e.render(r):r[e.key]??null},a=V&&e.editable===!0;return{key:String(e.key),header:n,align:e.align,priority:e.priority,width:e.width,render:a?(t,n)=>{let r=f(b(t,J(n)),e.key),a=X(t,e,r);return(0,d.jsx)(c.EditableCell,{text:e.formatEdit?e.formatEdit(t):String(a??``),columnLabel:p(e),rowNumber:n+1,inputType:e.editorType??`text`,editing:A===r,refocus:M===r,saving:R[r]===!0,error:I[r]??null,errorId:`tempest-cell-error-${r.replace(/[^\w-]/g,`_`)}`,labels:B,onOpen:()=>{j(r),N(null)},onCommit:(i,a)=>$(t,e,r,n,i,a),onCancel:()=>{j(null),N(r),L(e=>{let t={...e};return delete t[r],t})},children:i(t,a)})}:r}}),[h,T,V,A,M,R,I,B,P,J,$]);return(0,d.jsxs)(`div`,{className:e.cn(s.default.wrapper,te),...ne,children:[_&&(0,d.jsx)(i.SearchBar,{value:C,onChange:e=>{w(e),O(1)},wrapperClassName:s.default.search}),(0,d.jsx)(a.Table,{columns:ie,data:q,rowKey:(e,t)=>b(e,J(t)),emptyMessage:ee}),G>1&&(0,d.jsx)(r.Pagination,{page:K,totalPages:G,onPageChange:O,totalItems:W.length})]})}exports.DataTable=m;
1
+ const e=require("../../utils/cn.cjs"),t=require("../../hooks/use-pagination.cjs"),n=require("../../hooks/use-announce.cjs"),r=require("../Pagination/Pagination.cjs"),i=require("../SearchBar/SearchBar.cjs"),a=require("../Table/Table.cjs"),o=require("../../utils/compare-values.cjs"),s=require("./DataTable.module.cjs"),c=require("./EditableCell.cjs"),l=require("./edit-labels.cjs");let u=require("react"),d=require("react/jsx-runtime");function f(e,t){return`${String(e)}::${String(t)}`}function p(e){return typeof e.header==`string`?e.header:String(e.key)}function m({data:m,columns:h,pageSize:g=10,searchable:_=!1,searchKeys:v,initialSort:ee,rowKey:y=(e,t)=>t,emptyMessage:b,onCellChange:x,editLabels:S,className:C,...te}){let[w,ne]=(0,u.useState)(``),[T,E]=(0,u.useState)(ee??null),{page:D,setPage:O}=t.usePagination(1,g),k=n.useAnnounce(),[A,j]=(0,u.useState)(null),[M,N]=(0,u.useState)(null),[P,F]=(0,u.useState)({}),[I,L]=(0,u.useState)({}),[R,z]=(0,u.useState)({}),B=(0,u.useMemo)(()=>({...l.DEFAULT_EDIT_LABELS,...S}),[S]),V=x!==void 0&&h.some(e=>e.editable),H=(0,u.useMemo)(()=>v&&v.length>0?v:h.filter(e=>{let t=m.find(t=>t[e.key]!=null),n=t?t[e.key]:void 0;return typeof n==`string`||typeof n==`number`}).map(e=>e.key),[v,h,m]),U=(0,u.useMemo)(()=>{let e=w.trim().toLowerCase();return!e||!_?m:m.filter(t=>H.some(n=>{let r=t[n];return r!=null&&String(r).toLowerCase().includes(e)}))},[m,w,_,H]),W=(0,u.useMemo)(()=>{if(!T)return U;let e=T.direction===`asc`?1:-1;return[...U].sort((t,n)=>o.compareValues(t[T.key],n[T.key])*e)},[U,T]),G=Math.max(1,Math.ceil(W.length/g));(0,u.useEffect)(()=>{D>G&&O(G)},[D,G,O]);let K=Math.min(D,G),q=(0,u.useMemo)(()=>{let e=(K-1)*g;return W.slice(e,e+g)},[W,K,g]);function re(e){E(t=>!t||t.key!==e?{key:e,direction:`asc`}:t.direction===`asc`?{key:e,direction:`desc`}:null)}let J=(0,u.useCallback)(e=>(K-1)*g+e,[K,g]),Y=(0,u.useMemo)(()=>{if(!V)return[];let e=[];return q.forEach((t,n)=>{let r=y(t,J(n));for(let t of h)t.editable&&e.push(f(r,t.key))}),e},[V,q,h,J]),X=(0,u.useCallback)((e,t,n)=>n in P?P[n]:e[t.key],[P]),Z=(0,u.useCallback)(async(e,t,n)=>{z(t=>({...t,[e]:!0}));try{await x?.(n),k(B.saved(p(t)))}catch(n){F(t=>{let n={...t};return delete n[e],n});let r=n instanceof Error&&n.message?n.message:B.saveFailed(p(t));L(t=>({...t,[e]:r}))}finally{z(t=>{let n={...t};return delete n[e],n})}},[x,k,B]),Q=(0,u.useCallback)((e,t)=>{if(t===`none`){j(null),N(e);return}let n=Y.indexOf(e),r=Y[n+(t===`next`?1:-1)];if(r===void 0){j(null),N(e);return}j(r),N(null)},[Y]),$=(0,u.useCallback)((e,t,n,r,i,a)=>{let o=X(e,t,n);if(i===(t.formatEdit?t.formatEdit(e):String(o??``))){Q(n,a);return}let s=t.parse?t.parse(i,e):t.editorType===`number`?Number(i):i.trim(),c=t.validate?.(s,e)??null;if(c){L(e=>({...e,[n]:c}));return}L(e=>{let t={...e};return delete t[n],t}),F(e=>({...e,[n]:s})),Q(n,a),Z(n,t,{row:e,key:t.key,value:s,previous:o,rowIndex:J(r)})},[X,Q,Z,J]),ie=(0,u.useMemo)(()=>h.map(e=>{let t=T?.key===e.key?T?.direction===`asc`?` ▲`:` ▼`:``,n=e.sortable?(0,d.jsxs)(`button`,{type:`button`,className:s.default.sortButton,onClick:()=>re(e.key),"aria-label":`Ordenar por ${p(e)}`,children:[e.header,(0,d.jsx)(`span`,{className:s.default.sortIndicator,"aria-hidden":!0,children:t})]}):e.header,r=t=>e.render?e.render(t):t[e.key]??null,i=(t,n)=>{let r={...t,[e.key]:n};return e.render?e.render(r):r[e.key]??null},a=V&&e.editable===!0;return{key:String(e.key),header:n,align:e.align,priority:e.priority,width:e.width,render:a?(t,n)=>{let r=f(y(t,J(n)),e.key),a=X(t,e,r),o=e.formatEdit?e.formatEdit(t):String(a??``);return(0,d.jsx)(c.EditableCell,{text:o,columnLabel:p(e),rowNumber:n+1,inputType:e.editorType??`text`,editing:A===r,refocus:M===r,saving:R[r]===!0,error:I[r]??null,errorId:`tempest-cell-error-${r.replace(/[^\w-]/g,`_`)}`,labels:B,onOpen:()=>{j(r),N(null)},onCommit:(i,a)=>$(t,e,r,n,i,a),onCancel:()=>{j(null),N(r),L(e=>{let t={...e};return delete t[r],t})},children:i(t,a)})}:r}}),[h,T,V,A,M,R,I,B,P,J,$]);return(0,d.jsxs)(`div`,{className:e.cn(s.default.wrapper,C),...te,children:[_&&(0,d.jsx)(i.SearchBar,{value:w,onChange:e=>{ne(e),O(1)},wrapperClassName:s.default.search}),(0,d.jsx)(a.Table,{columns:ie,data:q,rowKey:(e,t)=>y(e,J(t)),emptyMessage:b}),G>1&&(0,d.jsx)(r.Pagination,{page:K,totalPages:G,onPageChange:O,totalItems:W.length})]})}exports.DataTable=m;
2
2
  //# sourceMappingURL=DataTable.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.cjs","names":[],"sources":["../../../src/components/DataTable/DataTable.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the table does four jobs\n * a caller turns on independently — paging (pageSize), search (searchable,\n * searchKeys), sort (initialSort) and inline edit (onCellChange, editLabels) — over\n * one row model (data, columns, rowKey, emptyMessage). The body is long because\n * those four share the derived-rows pipeline: filter, then sort, then page, then map\n * to cells, in that order and off the same memo.\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { compareValues } from \"@/utils/compare-values\";\nimport { usePagination } from \"@/hooks\";\nimport { useAnnounce } from \"@/hooks/use-announce\";\nimport { Table, type TableAlign, type TableColumn, type TablePriority } from \"../Table\";\nimport { Pagination } from \"../Pagination\";\nimport { SearchBar } from \"../SearchBar\";\nimport { EditableCell } from \"./EditableCell\";\nimport { DEFAULT_EDIT_LABELS, type CellCommitMove, type DataTableEditLabels } from \"./edit-labels\";\nimport styles from \"./DataTable.module.css\";\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport interface DataTableSort<T> {\n key: keyof T;\n direction: SortDirection;\n}\n\n/** Input types an editable column can use. */\nexport type DataTableEditorType = \"text\" | \"number\" | \"date\" | \"email\" | \"tel\" | \"url\";\n\n/** One accepted cell edit, handed to `onCellChange`. */\nexport interface DataTableCellChange<T> {\n /** The row as it was before the edit. */\n row: T;\n /** Which column changed. */\n key: keyof T;\n /** The parsed new value. */\n value: unknown;\n /** The value that was displayed before the edit. */\n previous: unknown;\n /** Index of the row in the full `data` array. */\n rowIndex: number;\n}\n\n/**\n * Column definition for {@link DataTable}. Extends the headless {@link Table}\n * column shape with a typed `key`, opt-in sorting, opt-in inline editing, and the\n * visual options that are forwarded to the underlying Table cell.\n */\nexport interface DataTableColumn<T> {\n /** Property of the row this column reads from. Doubles as the cell key. */\n key: keyof T;\n /** Column heading. */\n header: ReactNode;\n /** Custom cell renderer. Defaults to `String(row[key])`. */\n render?: (row: T) => ReactNode;\n /** Enable click-to-sort on this column's header. */\n sortable?: boolean;\n /** Text alignment forwarded to the Table cell. */\n align?: TableAlign;\n /** Responsive visibility priority forwarded to the Table cell. */\n priority?: TablePriority;\n /** Fixed column width forwarded to the Table cell. */\n width?: string | number;\n /**\n * Let cells in this column be edited in place. Requires `onCellChange` on the\n * table; without it the column stays read-only.\n */\n editable?: boolean;\n /** Editor input type. Default `\"text\"`. */\n editorType?: DataTableEditorType;\n /** Text the editor opens with. Defaults to `String(value ?? \"\")`. */\n formatEdit?: (row: T) => string;\n /**\n * Turn the typed string into the stored value. Defaults to the trimmed string,\n * or `Number(raw)` when `editorType` is `\"number\"`.\n */\n parse?: (raw: string, row: T) => unknown;\n /** Return a message to reject the edit, or `null` to accept it. */\n validate?: (value: unknown, row: T) => string | null;\n}\n\nexport interface DataTableProps<T> extends HTMLAttributes<HTMLDivElement> {\n /** Full, unfiltered dataset. Sorting/filtering/pagination happen client-side. */\n data: T[];\n /** Column definitions. */\n columns: DataTableColumn<T>[];\n /** Rows per page. Default 10. */\n pageSize?: number;\n /** Render a search input above the table. Default false. */\n searchable?: boolean;\n /**\n * Keys to match the search term against. When omitted, every column whose\n * value is a string or number is searched.\n */\n searchKeys?: (keyof T)[];\n /** Initial sort applied before any header interaction. */\n initialSort?: DataTableSort<T>;\n /** Stable key extractor for rows. Defaults to the row index. */\n rowKey?: (row: T, index: number) => string | number;\n /** Content shown when no rows match. */\n emptyMessage?: ReactNode;\n /**\n * Persist an accepted cell edit. Return a promise: while it is pending the cell\n * already shows the new value, and a rejection rolls that back and surfaces the\n * error in the cell. Without this prop no column is editable.\n */\n onCellChange?: (change: DataTableCellChange<T>) => void | Promise<void>;\n /** Override the PT-BR copy of the editing affordances. */\n editLabels?: Partial<DataTableEditLabels>;\n}\n\n/** Identity of one cell, stable across re-renders and pagination. */\nfunction cellId(rowKeyValue: string | number, columnKey: PropertyKey): string {\n return `${String(rowKeyValue)}::${String(columnKey)}`;\n}\n\nfunction headerText<T>(column: DataTableColumn<T>): string {\n return typeof column.header === \"string\" ? column.header : String(column.key);\n}\n\n/**\n * Stateful, headless data table built on top of {@link Table}. Adds\n * client-side searching, click-to-sort columns, pagination and opt-in inline\n * editing while delegating all table markup to the underlying Table component.\n *\n * - Clicking a sortable header cycles asc → desc → unsorted.\n * - Search matches a case-insensitive substring across `searchKeys`\n * (or every string/number column when not provided).\n * - Pagination is hidden when the result fits on a single page.\n * - A column with `editable` renders a button that opens an inline editor;\n * `Enter` commits, `Escape` discards, `Tab` walks to the next editable cell.\n *\n * Editing is strictly opt-in: with no `editable` column (or no `onCellChange`) the\n * rendered markup is byte-for-byte what it was before the feature existed, which\n * matters because the component is published.\n *\n * ## Optimistic, with a visible rollback\n *\n * An accepted edit is shown immediately and `onCellChange` runs in the background.\n * If it rejects, the cell returns to the old value **and** shows the reason as a\n * `role=\"alert\"` tied to the cell. A silent revert is worse than no optimistic\n * update at all: the user watched their edit appear and has no reason to doubt it.\n *\n * The header memo depends on `columns`, `sort` and the editing state only:\n * `toggleSort` and the commit callbacks are recreated each render but always close\n * over the same setters, so including them would rebuild every header on every\n * render without changing behaviour. That is why `exhaustive-deps` is silenced on\n * that dependency array.\n */\nexport function DataTable<T>({\n data,\n columns,\n pageSize = 10,\n searchable = false,\n searchKeys,\n initialSort,\n rowKey = (_row, index) => index,\n emptyMessage,\n onCellChange,\n editLabels,\n className,\n ...rest\n}: DataTableProps<T>) {\n const [search, setSearch] = useState<string>(\"\");\n const [sort, setSort] = useState<DataTableSort<T> | null>(initialSort ?? null);\n const { page, setPage } = usePagination(1, pageSize);\n const announce = useAnnounce();\n\n const [editing, setEditing] = useState<string | null>(null);\n const [refocus, setRefocus] = useState<string | null>(null);\n const [overrides, setOverrides] = useState<Record<string, unknown>>({});\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [saving, setSaving] = useState<Record<string, boolean>>({});\n\n const labels = useMemo<DataTableEditLabels>(\n () => ({ ...DEFAULT_EDIT_LABELS, ...editLabels }),\n [editLabels],\n );\n const editingEnabled = onCellChange !== undefined && columns.some((column) => column.editable);\n\n const effectiveSearchKeys = useMemo<(keyof T)[]>(() => {\n if (searchKeys && searchKeys.length > 0) return searchKeys;\n return columns\n .filter((column) => {\n const sample = data.find((row) => row[column.key] != null);\n const value = sample ? sample[column.key] : undefined;\n return typeof value === \"string\" || typeof value === \"number\";\n })\n .map((column) => column.key);\n }, [searchKeys, columns, data]);\n\n const filtered = useMemo<T[]>(() => {\n const term = search.trim().toLowerCase();\n if (!term || !searchable) return data;\n return data.filter((row) =>\n effectiveSearchKeys.some((key) => {\n const value = row[key];\n return value != null && String(value).toLowerCase().includes(term);\n }),\n );\n }, [data, search, searchable, effectiveSearchKeys]);\n\n const sorted = useMemo<T[]>(() => {\n if (!sort) return filtered;\n const factor = sort.direction === \"asc\" ? 1 : -1;\n return [...filtered].sort((a, b) => compareValues(a[sort.key], b[sort.key]) * factor);\n }, [filtered, sort]);\n\n const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));\n\n // Clamp the current page when the dataset shrinks (e.g. after filtering).\n useEffect(() => {\n if (page > totalPages) setPage(totalPages);\n }, [page, totalPages, setPage]);\n\n const safePage = Math.min(page, totalPages);\n const pageRows = useMemo<T[]>(() => {\n const start = (safePage - 1) * pageSize;\n return sorted.slice(start, start + pageSize);\n }, [sorted, safePage, pageSize]);\n\n function toggleSort(key: keyof T): void {\n setSort((current) => {\n if (!current || current.key !== key) return { key, direction: \"asc\" };\n if (current.direction === \"asc\") return { key, direction: \"desc\" };\n return null;\n });\n }\n\n const absoluteIndex = useCallback(\n (pageIndex: number) => (safePage - 1) * pageSize + pageIndex,\n [safePage, pageSize],\n );\n\n /**\n * Every editable cell on the page, row-major — the order `Tab` walks.\n *\n * Row-major and not column-major because a row is the record a user is\n * correcting; walking down a column would make them re-find their place on\n * every keystroke.\n */\n const editableCellIds = useMemo<string[]>(() => {\n if (!editingEnabled) return [];\n const ids: string[] = [];\n pageRows.forEach((row, index) => {\n const key = rowKey(row, absoluteIndex(index));\n for (const column of columns) {\n if (column.editable) ids.push(cellId(key, column.key));\n }\n });\n return ids;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editingEnabled, pageRows, columns, absoluteIndex]);\n\n const displayed = useCallback(\n (row: T, column: DataTableColumn<T>, id: string): unknown =>\n id in overrides ? overrides[id] : row[column.key],\n [overrides],\n );\n\n /**\n * Run the caller's `onCellChange` behind the optimistic update.\n *\n * Only the *success* is announced. The failure already renders as a\n * `role=\"alert\"` inside the cell, which screen readers read on insertion —\n * announcing it again from the shared region would read it twice and put the\n * same text in the document twice.\n */\n const persist = useCallback(\n async (id: string, column: DataTableColumn<T>, change: DataTableCellChange<T>) => {\n setSaving((current) => ({ ...current, [id]: true }));\n try {\n await onCellChange?.(change);\n announce(labels.saved(headerText(column)));\n } catch (error) {\n setOverrides((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n const message =\n error instanceof Error && error.message\n ? error.message\n : labels.saveFailed(headerText(column));\n setErrors((current) => ({ ...current, [id]: message }));\n } finally {\n setSaving((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n }\n },\n [onCellChange, announce, labels],\n );\n\n const moveFrom = useCallback(\n (id: string, move: CellCommitMove): void => {\n if (move === \"none\") {\n setEditing(null);\n setRefocus(id);\n return;\n }\n const index = editableCellIds.indexOf(id);\n const target = editableCellIds[index + (move === \"next\" ? 1 : -1)];\n if (target === undefined) {\n setEditing(null);\n setRefocus(id);\n return;\n }\n setEditing(target);\n setRefocus(null);\n },\n [editableCellIds],\n );\n\n /**\n * Parse, validate, stage optimistically, then save in the background.\n *\n * Validation runs before anything is staged, and a rejection leaves the editor\n * open with the message attached to the input — the user has to be able to fix\n * what they typed without retyping it.\n */\n const commit = useCallback(\n (\n row: T,\n column: DataTableColumn<T>,\n id: string,\n pageIndex: number,\n raw: string,\n move: CellCommitMove,\n ): void => {\n const previous = displayed(row, column, id);\n const currentText = column.formatEdit ? column.formatEdit(row) : String(previous ?? \"\");\n if (raw === currentText) {\n moveFrom(id, move);\n return;\n }\n\n const value = column.parse\n ? column.parse(raw, row)\n : column.editorType === \"number\"\n ? Number(raw)\n : raw.trim();\n\n const invalid = column.validate?.(value, row) ?? null;\n if (invalid) {\n setErrors((current) => ({ ...current, [id]: invalid }));\n return;\n }\n\n setErrors((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n setOverrides((current) => ({ ...current, [id]: value }));\n moveFrom(id, move);\n void persist(id, column, {\n row,\n key: column.key,\n value,\n previous,\n rowIndex: absoluteIndex(pageIndex),\n });\n },\n [displayed, moveFrom, persist, absoluteIndex],\n );\n\n const tableColumns = useMemo<TableColumn<T>[]>(\n () =>\n columns.map((column) => {\n const isSorted = sort?.key === column.key;\n const indicator = isSorted ? (sort?.direction === \"asc\" ? \" ▲\" : \" ▼\") : \"\";\n const header = column.sortable ? (\n <button\n type=\"button\"\n className={styles.sortButton}\n onClick={() => toggleSort(column.key)}\n aria-label={`Ordenar por ${headerText(column)}`}\n >\n {column.header}\n <span className={styles.sortIndicator} aria-hidden>\n {indicator}\n </span>\n </button>\n ) : (\n column.header\n );\n\n const plainCell = (row: T): ReactNode => {\n if (column.render) return column.render(row);\n return (row[column.key] as ReactNode) ?? null;\n };\n\n /**\n * Render an editable cell's content against the optimistic value.\n *\n * The row is shallow-patched rather than the value passed alongside it,\n * because a column with a custom `render` (a `<Money>`, a badge) reads\n * the row — handing it the stale row would show the old number under a\n * cell the user just changed.\n */\n const patchedCell = (row: T, value: unknown): ReactNode => {\n const patched = { ...row, [column.key]: value } as T;\n if (column.render) return column.render(patched);\n return (patched[column.key] as ReactNode) ?? null;\n };\n\n const editable = editingEnabled && column.editable === true;\n\n return {\n key: String(column.key),\n header,\n align: column.align,\n priority: column.priority,\n width: column.width,\n render: editable\n ? (row: T, index: number) => {\n const id = cellId(rowKey(row, absoluteIndex(index)), column.key);\n const value = displayed(row, column, id);\n const text = column.formatEdit\n ? column.formatEdit(row)\n : String(value ?? \"\");\n return (\n <EditableCell\n text={text}\n columnLabel={headerText(column)}\n rowNumber={index + 1}\n inputType={column.editorType ?? \"text\"}\n editing={editing === id}\n refocus={refocus === id}\n saving={saving[id] === true}\n error={errors[id] ?? null}\n errorId={`tempest-cell-error-${id.replace(/[^\\w-]/g, \"_\")}`}\n labels={labels}\n onOpen={() => {\n setEditing(id);\n setRefocus(null);\n }}\n onCommit={(raw, move) =>\n commit(row, column, id, index, raw, move)\n }\n onCancel={() => {\n setEditing(null);\n setRefocus(id);\n setErrors((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n }}\n >\n {patchedCell(row, value)}\n </EditableCell>\n );\n }\n : plainCell,\n };\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n columns,\n sort,\n editingEnabled,\n editing,\n refocus,\n saving,\n errors,\n labels,\n overrides,\n absoluteIndex,\n commit,\n ],\n );\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n {searchable && (\n <SearchBar\n value={search}\n onChange={(value) => {\n setSearch(value);\n setPage(1);\n }}\n wrapperClassName={styles.search}\n />\n )}\n <Table\n columns={tableColumns}\n data={pageRows}\n rowKey={(row, index) => rowKey(row, absoluteIndex(index))}\n emptyMessage={emptyMessage}\n />\n {totalPages > 1 && (\n <Pagination\n page={safePage}\n totalPages={totalPages}\n onPageChange={setPage}\n totalItems={sorted.length}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataTable.cjs","names":[],"sources":["../../../src/components/DataTable/DataTable.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the table does four jobs\n * a caller turns on independently — paging (pageSize), search (searchable,\n * searchKeys), sort (initialSort) and inline edit (onCellChange, editLabels) — over\n * one row model (data, columns, rowKey, emptyMessage). The body is long because\n * those four share the derived-rows pipeline: filter, then sort, then page, then map\n * to cells, in that order and off the same memo.\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { compareValues } from \"@/utils/compare-values\";\nimport { usePagination } from \"@/hooks\";\nimport { useAnnounce } from \"@/hooks/use-announce\";\nimport { Table, type TableAlign, type TableColumn, type TablePriority } from \"../Table\";\nimport { Pagination } from \"../Pagination\";\nimport { SearchBar } from \"../SearchBar\";\nimport { EditableCell } from \"./EditableCell\";\nimport { DEFAULT_EDIT_LABELS, type CellCommitMove, type DataTableEditLabels } from \"./edit-labels\";\nimport styles from \"./DataTable.module.css\";\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport interface DataTableSort<T> {\n key: keyof T;\n direction: SortDirection;\n}\n\n/** Input types an editable column can use. */\nexport type DataTableEditorType = \"text\" | \"number\" | \"date\" | \"email\" | \"tel\" | \"url\";\n\n/** One accepted cell edit, handed to `onCellChange`. */\nexport interface DataTableCellChange<T> {\n /** The row as it was before the edit. */\n row: T;\n /** Which column changed. */\n key: keyof T;\n /** The parsed new value. */\n value: unknown;\n /** The value that was displayed before the edit. */\n previous: unknown;\n /** Index of the row in the full `data` array. */\n rowIndex: number;\n}\n\n/**\n * Column definition for {@link DataTable}. Extends the headless {@link Table}\n * column shape with a typed `key`, opt-in sorting, opt-in inline editing, and the\n * visual options that are forwarded to the underlying Table cell.\n */\nexport interface DataTableColumn<T> {\n /** Property of the row this column reads from. Doubles as the cell key. */\n key: keyof T;\n /** Column heading. */\n header: ReactNode;\n /** Custom cell renderer. Defaults to `String(row[key])`. */\n render?: (row: T) => ReactNode;\n /** Enable click-to-sort on this column's header. */\n sortable?: boolean;\n /** Text alignment forwarded to the Table cell. */\n align?: TableAlign;\n /** Responsive visibility priority forwarded to the Table cell. */\n priority?: TablePriority;\n /** Fixed column width forwarded to the Table cell. */\n width?: string | number;\n /**\n * Let cells in this column be edited in place. Requires `onCellChange` on the\n * table; without it the column stays read-only.\n */\n editable?: boolean;\n /** Editor input type. Default `\"text\"`. */\n editorType?: DataTableEditorType;\n /** Text the editor opens with. Defaults to `String(value ?? \"\")`. */\n formatEdit?: (row: T) => string;\n /**\n * Turn the typed string into the stored value. Defaults to the trimmed string,\n * or `Number(raw)` when `editorType` is `\"number\"`.\n */\n parse?: (raw: string, row: T) => unknown;\n /** Return a message to reject the edit, or `null` to accept it. */\n validate?: (value: unknown, row: T) => string | null;\n}\n\nexport interface DataTableProps<T> extends HTMLAttributes<HTMLDivElement> {\n /** Full, unfiltered dataset. Sorting/filtering/pagination happen client-side. */\n data: T[];\n /** Column definitions. */\n columns: DataTableColumn<T>[];\n /** Rows per page. Default 10. */\n pageSize?: number;\n /** Render a search input above the table. Default false. */\n searchable?: boolean;\n /**\n * Keys to match the search term against. When omitted, every column whose\n * value is a string or number is searched.\n */\n searchKeys?: (keyof T)[];\n /** Initial sort applied before any header interaction. */\n initialSort?: DataTableSort<T>;\n /** Stable key extractor for rows. Defaults to the row index. */\n rowKey?: (row: T, index: number) => string | number;\n /** Content shown when no rows match. */\n emptyMessage?: ReactNode;\n /**\n * Persist an accepted cell edit. Return a promise: while it is pending the cell\n * already shows the new value, and a rejection rolls that back and surfaces the\n * error in the cell. Without this prop no column is editable.\n */\n onCellChange?: (change: DataTableCellChange<T>) => void | Promise<void>;\n /** Override the PT-BR copy of the editing affordances. */\n editLabels?: Partial<DataTableEditLabels>;\n}\n\n/** Identity of one cell, stable across re-renders and pagination. */\nfunction cellId(rowKeyValue: string | number, columnKey: PropertyKey): string {\n return `${String(rowKeyValue)}::${String(columnKey)}`;\n}\n\nfunction headerText<T>(column: DataTableColumn<T>): string {\n return typeof column.header === \"string\" ? column.header : String(column.key);\n}\n\n/**\n * Stateful, headless data table built on top of {@link Table}. Adds\n * client-side searching, click-to-sort columns, pagination and opt-in inline\n * editing while delegating all table markup to the underlying Table component.\n *\n * - Clicking a sortable header cycles asc → desc → unsorted.\n * - Search matches a case-insensitive substring across `searchKeys`\n * (or every string/number column when not provided).\n * - Pagination is hidden when the result fits on a single page.\n * - A column with `editable` renders a button that opens an inline editor;\n * `Enter` commits, `Escape` discards, `Tab` walks to the next editable cell.\n *\n * Editing is strictly opt-in: with no `editable` column (or no `onCellChange`) the\n * rendered markup is byte-for-byte what it was before the feature existed, which\n * matters because the component is published.\n *\n * ## Optimistic, with a visible rollback\n *\n * An accepted edit is shown immediately and `onCellChange` runs in the background.\n * If it rejects, the cell returns to the old value **and** shows the reason as a\n * `role=\"alert\"` tied to the cell. A silent revert is worse than no optimistic\n * update at all: the user watched their edit appear and has no reason to doubt it.\n *\n * The header memo depends on `columns`, `sort` and the editing state only:\n * `toggleSort` and the commit callbacks are recreated each render but always close\n * over the same setters, so including them would rebuild every header on every\n * render without changing behaviour. That is why `exhaustive-deps` is silenced on\n * that dependency array.\n */\nexport function DataTable<T>({\n data,\n columns,\n pageSize = 10,\n searchable = false,\n searchKeys,\n initialSort,\n rowKey = (_row, index) => index,\n emptyMessage,\n onCellChange,\n editLabels,\n className,\n ...rest\n}: DataTableProps<T>) {\n const [search, setSearch] = useState<string>(\"\");\n const [sort, setSort] = useState<DataTableSort<T> | null>(initialSort ?? null);\n const { page, setPage } = usePagination(1, pageSize);\n const announce = useAnnounce();\n\n const [editing, setEditing] = useState<string | null>(null);\n const [refocus, setRefocus] = useState<string | null>(null);\n const [overrides, setOverrides] = useState<Record<string, unknown>>({});\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [saving, setSaving] = useState<Record<string, boolean>>({});\n\n const labels = useMemo<DataTableEditLabels>(\n () => ({ ...DEFAULT_EDIT_LABELS, ...editLabels }),\n [editLabels],\n );\n const editingEnabled = onCellChange !== undefined && columns.some((column) => column.editable);\n\n const effectiveSearchKeys = useMemo<(keyof T)[]>(() => {\n if (searchKeys && searchKeys.length > 0) return searchKeys;\n return columns\n .filter((column) => {\n const sample = data.find((row) => row[column.key] != null);\n const value = sample ? sample[column.key] : undefined;\n return typeof value === \"string\" || typeof value === \"number\";\n })\n .map((column) => column.key);\n }, [searchKeys, columns, data]);\n\n const filtered = useMemo<T[]>(() => {\n const term = search.trim().toLowerCase();\n if (!term || !searchable) return data;\n return data.filter((row) =>\n effectiveSearchKeys.some((key) => {\n const value = row[key];\n return value != null && String(value).toLowerCase().includes(term);\n }),\n );\n }, [data, search, searchable, effectiveSearchKeys]);\n\n const sorted = useMemo<T[]>(() => {\n if (!sort) return filtered;\n const factor = sort.direction === \"asc\" ? 1 : -1;\n return [...filtered].sort((a, b) => compareValues(a[sort.key], b[sort.key]) * factor);\n }, [filtered, sort]);\n\n const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));\n\n // Clamp the current page when the dataset shrinks (e.g. after filtering).\n useEffect(() => {\n if (page > totalPages) setPage(totalPages);\n }, [page, totalPages, setPage]);\n\n const safePage = Math.min(page, totalPages);\n const pageRows = useMemo<T[]>(() => {\n const start = (safePage - 1) * pageSize;\n return sorted.slice(start, start + pageSize);\n }, [sorted, safePage, pageSize]);\n\n function toggleSort(key: keyof T): void {\n setSort((current) => {\n if (!current || current.key !== key) return { key, direction: \"asc\" };\n if (current.direction === \"asc\") return { key, direction: \"desc\" };\n return null;\n });\n }\n\n const absoluteIndex = useCallback(\n (pageIndex: number) => (safePage - 1) * pageSize + pageIndex,\n [safePage, pageSize],\n );\n\n /**\n * Every editable cell on the page, row-major — the order `Tab` walks.\n *\n * Row-major and not column-major because a row is the record a user is\n * correcting; walking down a column would make them re-find their place on\n * every keystroke.\n */\n const editableCellIds = useMemo<string[]>(() => {\n if (!editingEnabled) return [];\n const ids: string[] = [];\n pageRows.forEach((row, index) => {\n const key = rowKey(row, absoluteIndex(index));\n for (const column of columns) {\n if (column.editable) ids.push(cellId(key, column.key));\n }\n });\n return ids;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editingEnabled, pageRows, columns, absoluteIndex]);\n\n const displayed = useCallback(\n (row: T, column: DataTableColumn<T>, id: string): unknown =>\n id in overrides ? overrides[id] : row[column.key],\n [overrides],\n );\n\n /**\n * Run the caller's `onCellChange` behind the optimistic update.\n *\n * Only the *success* is announced. The failure already renders as a\n * `role=\"alert\"` inside the cell, which screen readers read on insertion —\n * announcing it again from the shared region would read it twice and put the\n * same text in the document twice.\n */\n const persist = useCallback(\n async (id: string, column: DataTableColumn<T>, change: DataTableCellChange<T>) => {\n setSaving((current) => ({ ...current, [id]: true }));\n try {\n await onCellChange?.(change);\n announce(labels.saved(headerText(column)));\n } catch (error) {\n setOverrides((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n const message =\n error instanceof Error && error.message\n ? error.message\n : labels.saveFailed(headerText(column));\n setErrors((current) => ({ ...current, [id]: message }));\n } finally {\n setSaving((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n }\n },\n [onCellChange, announce, labels],\n );\n\n const moveFrom = useCallback(\n (id: string, move: CellCommitMove): void => {\n if (move === \"none\") {\n setEditing(null);\n setRefocus(id);\n return;\n }\n const index = editableCellIds.indexOf(id);\n const target = editableCellIds[index + (move === \"next\" ? 1 : -1)];\n if (target === undefined) {\n setEditing(null);\n setRefocus(id);\n return;\n }\n setEditing(target);\n setRefocus(null);\n },\n [editableCellIds],\n );\n\n /**\n * Parse, validate, stage optimistically, then save in the background.\n *\n * Validation runs before anything is staged, and a rejection leaves the editor\n * open with the message attached to the input — the user has to be able to fix\n * what they typed without retyping it.\n */\n const commit = useCallback(\n (\n row: T,\n column: DataTableColumn<T>,\n id: string,\n pageIndex: number,\n raw: string,\n move: CellCommitMove,\n ): void => {\n const previous = displayed(row, column, id);\n const currentText = column.formatEdit ? column.formatEdit(row) : String(previous ?? \"\");\n if (raw === currentText) {\n moveFrom(id, move);\n return;\n }\n\n const value = column.parse\n ? column.parse(raw, row)\n : column.editorType === \"number\"\n ? Number(raw)\n : raw.trim();\n\n const invalid = column.validate?.(value, row) ?? null;\n if (invalid) {\n setErrors((current) => ({ ...current, [id]: invalid }));\n return;\n }\n\n setErrors((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n setOverrides((current) => ({ ...current, [id]: value }));\n moveFrom(id, move);\n void persist(id, column, {\n row,\n key: column.key,\n value,\n previous,\n rowIndex: absoluteIndex(pageIndex),\n });\n },\n [displayed, moveFrom, persist, absoluteIndex],\n );\n\n const tableColumns = useMemo<TableColumn<T>[]>(\n () =>\n columns.map((column) => {\n const isSorted = sort?.key === column.key;\n const indicator = isSorted ? (sort?.direction === \"asc\" ? \" ▲\" : \" ▼\") : \"\";\n const header = column.sortable ? (\n <button\n type=\"button\"\n className={styles.sortButton}\n onClick={() => toggleSort(column.key)}\n aria-label={`Ordenar por ${headerText(column)}`}\n >\n {column.header}\n <span className={styles.sortIndicator} aria-hidden>\n {indicator}\n </span>\n </button>\n ) : (\n column.header\n );\n\n const plainCell = (row: T): ReactNode => {\n if (column.render) return column.render(row);\n return (row[column.key] as ReactNode) ?? null;\n };\n\n /**\n * Render an editable cell's content against the optimistic value.\n *\n * The row is shallow-patched rather than the value passed alongside it,\n * because a column with a custom `render` (a `<Money>`, a badge) reads\n * the row — handing it the stale row would show the old number under a\n * cell the user just changed.\n */\n const patchedCell = (row: T, value: unknown): ReactNode => {\n const patched = { ...row, [column.key]: value } as T;\n if (column.render) return column.render(patched);\n return (patched[column.key] as ReactNode) ?? null;\n };\n\n const editable = editingEnabled && column.editable === true;\n\n return {\n key: String(column.key),\n header,\n align: column.align,\n priority: column.priority,\n width: column.width,\n render: editable\n ? (row: T, index: number) => {\n const id = cellId(rowKey(row, absoluteIndex(index)), column.key);\n const value = displayed(row, column, id);\n const text = column.formatEdit\n ? column.formatEdit(row)\n : String(value ?? \"\");\n return (\n <EditableCell\n text={text}\n columnLabel={headerText(column)}\n rowNumber={index + 1}\n inputType={column.editorType ?? \"text\"}\n editing={editing === id}\n refocus={refocus === id}\n saving={saving[id] === true}\n error={errors[id] ?? null}\n errorId={`tempest-cell-error-${id.replace(/[^\\w-]/g, \"_\")}`}\n labels={labels}\n onOpen={() => {\n setEditing(id);\n setRefocus(null);\n }}\n onCommit={(raw, move) =>\n commit(row, column, id, index, raw, move)\n }\n onCancel={() => {\n setEditing(null);\n setRefocus(id);\n setErrors((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n }}\n >\n {patchedCell(row, value)}\n </EditableCell>\n );\n }\n : plainCell,\n };\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n columns,\n sort,\n editingEnabled,\n editing,\n refocus,\n saving,\n errors,\n labels,\n overrides,\n absoluteIndex,\n commit,\n ],\n );\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n {searchable && (\n <SearchBar\n value={search}\n onChange={(value) => {\n setSearch(value);\n setPage(1);\n }}\n wrapperClassName={styles.search}\n />\n )}\n <Table\n columns={tableColumns}\n data={pageRows}\n rowKey={(row, index) => rowKey(row, absoluteIndex(index))}\n emptyMessage={emptyMessage}\n />\n {totalPages > 1 && (\n <Pagination\n page={safePage}\n totalPages={totalPages}\n onPageChange={setPage}\n totalItems={sorted.length}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -175,9 +175,9 @@ function g({ data: g, columns: _, pageSize: v = 10, searchable: y = !1, searchKe
175
175
  priority: e.priority,
176
176
  width: e.width,
177
177
  render: a ? (t, n) => {
178
- let r = m(x(t, J(n)), e.key), a = X(t, e, r);
178
+ let r = m(x(t, J(n)), e.key), a = X(t, e, r), o = e.formatEdit ? e.formatEdit(t) : String(a ?? "");
179
179
  return /* @__PURE__ */ f(c, {
180
- text: e.formatEdit ? e.formatEdit(t) : String(a ?? ""),
180
+ text: o,
181
181
  columnLabel: h(e),
182
182
  rowNumber: n + 1,
183
183
  inputType: e.editorType ?? "text",
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.js","names":[],"sources":["../../../src/components/DataTable/DataTable.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the table does four jobs\n * a caller turns on independently — paging (pageSize), search (searchable,\n * searchKeys), sort (initialSort) and inline edit (onCellChange, editLabels) — over\n * one row model (data, columns, rowKey, emptyMessage). The body is long because\n * those four share the derived-rows pipeline: filter, then sort, then page, then map\n * to cells, in that order and off the same memo.\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { compareValues } from \"@/utils/compare-values\";\nimport { usePagination } from \"@/hooks\";\nimport { useAnnounce } from \"@/hooks/use-announce\";\nimport { Table, type TableAlign, type TableColumn, type TablePriority } from \"../Table\";\nimport { Pagination } from \"../Pagination\";\nimport { SearchBar } from \"../SearchBar\";\nimport { EditableCell } from \"./EditableCell\";\nimport { DEFAULT_EDIT_LABELS, type CellCommitMove, type DataTableEditLabels } from \"./edit-labels\";\nimport styles from \"./DataTable.module.css\";\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport interface DataTableSort<T> {\n key: keyof T;\n direction: SortDirection;\n}\n\n/** Input types an editable column can use. */\nexport type DataTableEditorType = \"text\" | \"number\" | \"date\" | \"email\" | \"tel\" | \"url\";\n\n/** One accepted cell edit, handed to `onCellChange`. */\nexport interface DataTableCellChange<T> {\n /** The row as it was before the edit. */\n row: T;\n /** Which column changed. */\n key: keyof T;\n /** The parsed new value. */\n value: unknown;\n /** The value that was displayed before the edit. */\n previous: unknown;\n /** Index of the row in the full `data` array. */\n rowIndex: number;\n}\n\n/**\n * Column definition for {@link DataTable}. Extends the headless {@link Table}\n * column shape with a typed `key`, opt-in sorting, opt-in inline editing, and the\n * visual options that are forwarded to the underlying Table cell.\n */\nexport interface DataTableColumn<T> {\n /** Property of the row this column reads from. Doubles as the cell key. */\n key: keyof T;\n /** Column heading. */\n header: ReactNode;\n /** Custom cell renderer. Defaults to `String(row[key])`. */\n render?: (row: T) => ReactNode;\n /** Enable click-to-sort on this column's header. */\n sortable?: boolean;\n /** Text alignment forwarded to the Table cell. */\n align?: TableAlign;\n /** Responsive visibility priority forwarded to the Table cell. */\n priority?: TablePriority;\n /** Fixed column width forwarded to the Table cell. */\n width?: string | number;\n /**\n * Let cells in this column be edited in place. Requires `onCellChange` on the\n * table; without it the column stays read-only.\n */\n editable?: boolean;\n /** Editor input type. Default `\"text\"`. */\n editorType?: DataTableEditorType;\n /** Text the editor opens with. Defaults to `String(value ?? \"\")`. */\n formatEdit?: (row: T) => string;\n /**\n * Turn the typed string into the stored value. Defaults to the trimmed string,\n * or `Number(raw)` when `editorType` is `\"number\"`.\n */\n parse?: (raw: string, row: T) => unknown;\n /** Return a message to reject the edit, or `null` to accept it. */\n validate?: (value: unknown, row: T) => string | null;\n}\n\nexport interface DataTableProps<T> extends HTMLAttributes<HTMLDivElement> {\n /** Full, unfiltered dataset. Sorting/filtering/pagination happen client-side. */\n data: T[];\n /** Column definitions. */\n columns: DataTableColumn<T>[];\n /** Rows per page. Default 10. */\n pageSize?: number;\n /** Render a search input above the table. Default false. */\n searchable?: boolean;\n /**\n * Keys to match the search term against. When omitted, every column whose\n * value is a string or number is searched.\n */\n searchKeys?: (keyof T)[];\n /** Initial sort applied before any header interaction. */\n initialSort?: DataTableSort<T>;\n /** Stable key extractor for rows. Defaults to the row index. */\n rowKey?: (row: T, index: number) => string | number;\n /** Content shown when no rows match. */\n emptyMessage?: ReactNode;\n /**\n * Persist an accepted cell edit. Return a promise: while it is pending the cell\n * already shows the new value, and a rejection rolls that back and surfaces the\n * error in the cell. Without this prop no column is editable.\n */\n onCellChange?: (change: DataTableCellChange<T>) => void | Promise<void>;\n /** Override the PT-BR copy of the editing affordances. */\n editLabels?: Partial<DataTableEditLabels>;\n}\n\n/** Identity of one cell, stable across re-renders and pagination. */\nfunction cellId(rowKeyValue: string | number, columnKey: PropertyKey): string {\n return `${String(rowKeyValue)}::${String(columnKey)}`;\n}\n\nfunction headerText<T>(column: DataTableColumn<T>): string {\n return typeof column.header === \"string\" ? column.header : String(column.key);\n}\n\n/**\n * Stateful, headless data table built on top of {@link Table}. Adds\n * client-side searching, click-to-sort columns, pagination and opt-in inline\n * editing while delegating all table markup to the underlying Table component.\n *\n * - Clicking a sortable header cycles asc → desc → unsorted.\n * - Search matches a case-insensitive substring across `searchKeys`\n * (or every string/number column when not provided).\n * - Pagination is hidden when the result fits on a single page.\n * - A column with `editable` renders a button that opens an inline editor;\n * `Enter` commits, `Escape` discards, `Tab` walks to the next editable cell.\n *\n * Editing is strictly opt-in: with no `editable` column (or no `onCellChange`) the\n * rendered markup is byte-for-byte what it was before the feature existed, which\n * matters because the component is published.\n *\n * ## Optimistic, with a visible rollback\n *\n * An accepted edit is shown immediately and `onCellChange` runs in the background.\n * If it rejects, the cell returns to the old value **and** shows the reason as a\n * `role=\"alert\"` tied to the cell. A silent revert is worse than no optimistic\n * update at all: the user watched their edit appear and has no reason to doubt it.\n *\n * The header memo depends on `columns`, `sort` and the editing state only:\n * `toggleSort` and the commit callbacks are recreated each render but always close\n * over the same setters, so including them would rebuild every header on every\n * render without changing behaviour. That is why `exhaustive-deps` is silenced on\n * that dependency array.\n */\nexport function DataTable<T>({\n data,\n columns,\n pageSize = 10,\n searchable = false,\n searchKeys,\n initialSort,\n rowKey = (_row, index) => index,\n emptyMessage,\n onCellChange,\n editLabels,\n className,\n ...rest\n}: DataTableProps<T>) {\n const [search, setSearch] = useState<string>(\"\");\n const [sort, setSort] = useState<DataTableSort<T> | null>(initialSort ?? null);\n const { page, setPage } = usePagination(1, pageSize);\n const announce = useAnnounce();\n\n const [editing, setEditing] = useState<string | null>(null);\n const [refocus, setRefocus] = useState<string | null>(null);\n const [overrides, setOverrides] = useState<Record<string, unknown>>({});\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [saving, setSaving] = useState<Record<string, boolean>>({});\n\n const labels = useMemo<DataTableEditLabels>(\n () => ({ ...DEFAULT_EDIT_LABELS, ...editLabels }),\n [editLabels],\n );\n const editingEnabled = onCellChange !== undefined && columns.some((column) => column.editable);\n\n const effectiveSearchKeys = useMemo<(keyof T)[]>(() => {\n if (searchKeys && searchKeys.length > 0) return searchKeys;\n return columns\n .filter((column) => {\n const sample = data.find((row) => row[column.key] != null);\n const value = sample ? sample[column.key] : undefined;\n return typeof value === \"string\" || typeof value === \"number\";\n })\n .map((column) => column.key);\n }, [searchKeys, columns, data]);\n\n const filtered = useMemo<T[]>(() => {\n const term = search.trim().toLowerCase();\n if (!term || !searchable) return data;\n return data.filter((row) =>\n effectiveSearchKeys.some((key) => {\n const value = row[key];\n return value != null && String(value).toLowerCase().includes(term);\n }),\n );\n }, [data, search, searchable, effectiveSearchKeys]);\n\n const sorted = useMemo<T[]>(() => {\n if (!sort) return filtered;\n const factor = sort.direction === \"asc\" ? 1 : -1;\n return [...filtered].sort((a, b) => compareValues(a[sort.key], b[sort.key]) * factor);\n }, [filtered, sort]);\n\n const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));\n\n // Clamp the current page when the dataset shrinks (e.g. after filtering).\n useEffect(() => {\n if (page > totalPages) setPage(totalPages);\n }, [page, totalPages, setPage]);\n\n const safePage = Math.min(page, totalPages);\n const pageRows = useMemo<T[]>(() => {\n const start = (safePage - 1) * pageSize;\n return sorted.slice(start, start + pageSize);\n }, [sorted, safePage, pageSize]);\n\n function toggleSort(key: keyof T): void {\n setSort((current) => {\n if (!current || current.key !== key) return { key, direction: \"asc\" };\n if (current.direction === \"asc\") return { key, direction: \"desc\" };\n return null;\n });\n }\n\n const absoluteIndex = useCallback(\n (pageIndex: number) => (safePage - 1) * pageSize + pageIndex,\n [safePage, pageSize],\n );\n\n /**\n * Every editable cell on the page, row-major — the order `Tab` walks.\n *\n * Row-major and not column-major because a row is the record a user is\n * correcting; walking down a column would make them re-find their place on\n * every keystroke.\n */\n const editableCellIds = useMemo<string[]>(() => {\n if (!editingEnabled) return [];\n const ids: string[] = [];\n pageRows.forEach((row, index) => {\n const key = rowKey(row, absoluteIndex(index));\n for (const column of columns) {\n if (column.editable) ids.push(cellId(key, column.key));\n }\n });\n return ids;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editingEnabled, pageRows, columns, absoluteIndex]);\n\n const displayed = useCallback(\n (row: T, column: DataTableColumn<T>, id: string): unknown =>\n id in overrides ? overrides[id] : row[column.key],\n [overrides],\n );\n\n /**\n * Run the caller's `onCellChange` behind the optimistic update.\n *\n * Only the *success* is announced. The failure already renders as a\n * `role=\"alert\"` inside the cell, which screen readers read on insertion —\n * announcing it again from the shared region would read it twice and put the\n * same text in the document twice.\n */\n const persist = useCallback(\n async (id: string, column: DataTableColumn<T>, change: DataTableCellChange<T>) => {\n setSaving((current) => ({ ...current, [id]: true }));\n try {\n await onCellChange?.(change);\n announce(labels.saved(headerText(column)));\n } catch (error) {\n setOverrides((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n const message =\n error instanceof Error && error.message\n ? error.message\n : labels.saveFailed(headerText(column));\n setErrors((current) => ({ ...current, [id]: message }));\n } finally {\n setSaving((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n }\n },\n [onCellChange, announce, labels],\n );\n\n const moveFrom = useCallback(\n (id: string, move: CellCommitMove): void => {\n if (move === \"none\") {\n setEditing(null);\n setRefocus(id);\n return;\n }\n const index = editableCellIds.indexOf(id);\n const target = editableCellIds[index + (move === \"next\" ? 1 : -1)];\n if (target === undefined) {\n setEditing(null);\n setRefocus(id);\n return;\n }\n setEditing(target);\n setRefocus(null);\n },\n [editableCellIds],\n );\n\n /**\n * Parse, validate, stage optimistically, then save in the background.\n *\n * Validation runs before anything is staged, and a rejection leaves the editor\n * open with the message attached to the input — the user has to be able to fix\n * what they typed without retyping it.\n */\n const commit = useCallback(\n (\n row: T,\n column: DataTableColumn<T>,\n id: string,\n pageIndex: number,\n raw: string,\n move: CellCommitMove,\n ): void => {\n const previous = displayed(row, column, id);\n const currentText = column.formatEdit ? column.formatEdit(row) : String(previous ?? \"\");\n if (raw === currentText) {\n moveFrom(id, move);\n return;\n }\n\n const value = column.parse\n ? column.parse(raw, row)\n : column.editorType === \"number\"\n ? Number(raw)\n : raw.trim();\n\n const invalid = column.validate?.(value, row) ?? null;\n if (invalid) {\n setErrors((current) => ({ ...current, [id]: invalid }));\n return;\n }\n\n setErrors((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n setOverrides((current) => ({ ...current, [id]: value }));\n moveFrom(id, move);\n void persist(id, column, {\n row,\n key: column.key,\n value,\n previous,\n rowIndex: absoluteIndex(pageIndex),\n });\n },\n [displayed, moveFrom, persist, absoluteIndex],\n );\n\n const tableColumns = useMemo<TableColumn<T>[]>(\n () =>\n columns.map((column) => {\n const isSorted = sort?.key === column.key;\n const indicator = isSorted ? (sort?.direction === \"asc\" ? \" ▲\" : \" ▼\") : \"\";\n const header = column.sortable ? (\n <button\n type=\"button\"\n className={styles.sortButton}\n onClick={() => toggleSort(column.key)}\n aria-label={`Ordenar por ${headerText(column)}`}\n >\n {column.header}\n <span className={styles.sortIndicator} aria-hidden>\n {indicator}\n </span>\n </button>\n ) : (\n column.header\n );\n\n const plainCell = (row: T): ReactNode => {\n if (column.render) return column.render(row);\n return (row[column.key] as ReactNode) ?? null;\n };\n\n /**\n * Render an editable cell's content against the optimistic value.\n *\n * The row is shallow-patched rather than the value passed alongside it,\n * because a column with a custom `render` (a `<Money>`, a badge) reads\n * the row — handing it the stale row would show the old number under a\n * cell the user just changed.\n */\n const patchedCell = (row: T, value: unknown): ReactNode => {\n const patched = { ...row, [column.key]: value } as T;\n if (column.render) return column.render(patched);\n return (patched[column.key] as ReactNode) ?? null;\n };\n\n const editable = editingEnabled && column.editable === true;\n\n return {\n key: String(column.key),\n header,\n align: column.align,\n priority: column.priority,\n width: column.width,\n render: editable\n ? (row: T, index: number) => {\n const id = cellId(rowKey(row, absoluteIndex(index)), column.key);\n const value = displayed(row, column, id);\n const text = column.formatEdit\n ? column.formatEdit(row)\n : String(value ?? \"\");\n return (\n <EditableCell\n text={text}\n columnLabel={headerText(column)}\n rowNumber={index + 1}\n inputType={column.editorType ?? \"text\"}\n editing={editing === id}\n refocus={refocus === id}\n saving={saving[id] === true}\n error={errors[id] ?? null}\n errorId={`tempest-cell-error-${id.replace(/[^\\w-]/g, \"_\")}`}\n labels={labels}\n onOpen={() => {\n setEditing(id);\n setRefocus(null);\n }}\n onCommit={(raw, move) =>\n commit(row, column, id, index, raw, move)\n }\n onCancel={() => {\n setEditing(null);\n setRefocus(id);\n setErrors((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n }}\n >\n {patchedCell(row, value)}\n </EditableCell>\n );\n }\n : plainCell,\n };\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n columns,\n sort,\n editingEnabled,\n editing,\n refocus,\n saving,\n errors,\n labels,\n overrides,\n absoluteIndex,\n commit,\n ],\n );\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n {searchable && (\n <SearchBar\n value={search}\n onChange={(value) => {\n setSearch(value);\n setPage(1);\n }}\n wrapperClassName={styles.search}\n />\n )}\n <Table\n columns={tableColumns}\n data={pageRows}\n rowKey={(row, index) => rowKey(row, absoluteIndex(index))}\n emptyMessage={emptyMessage}\n />\n {totalPages > 1 && (\n <Pagination\n page={safePage}\n totalPages={totalPages}\n onPageChange={setPage}\n totalItems={sorted.length}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataTable.js","names":[],"sources":["../../../src/components/DataTable/DataTable.tsx"],"sourcesContent":["/**\n * @tempest-limits file-lines, props-count, function-lines — the table does four jobs\n * a caller turns on independently — paging (pageSize), search (searchable,\n * searchKeys), sort (initialSort) and inline edit (onCellChange, editLabels) — over\n * one row model (data, columns, rowKey, emptyMessage). The body is long because\n * those four share the derived-rows pipeline: filter, then sort, then page, then map\n * to cells, in that order and off the same memo.\n */\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { compareValues } from \"@/utils/compare-values\";\nimport { usePagination } from \"@/hooks\";\nimport { useAnnounce } from \"@/hooks/use-announce\";\nimport { Table, type TableAlign, type TableColumn, type TablePriority } from \"../Table\";\nimport { Pagination } from \"../Pagination\";\nimport { SearchBar } from \"../SearchBar\";\nimport { EditableCell } from \"./EditableCell\";\nimport { DEFAULT_EDIT_LABELS, type CellCommitMove, type DataTableEditLabels } from \"./edit-labels\";\nimport styles from \"./DataTable.module.css\";\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport interface DataTableSort<T> {\n key: keyof T;\n direction: SortDirection;\n}\n\n/** Input types an editable column can use. */\nexport type DataTableEditorType = \"text\" | \"number\" | \"date\" | \"email\" | \"tel\" | \"url\";\n\n/** One accepted cell edit, handed to `onCellChange`. */\nexport interface DataTableCellChange<T> {\n /** The row as it was before the edit. */\n row: T;\n /** Which column changed. */\n key: keyof T;\n /** The parsed new value. */\n value: unknown;\n /** The value that was displayed before the edit. */\n previous: unknown;\n /** Index of the row in the full `data` array. */\n rowIndex: number;\n}\n\n/**\n * Column definition for {@link DataTable}. Extends the headless {@link Table}\n * column shape with a typed `key`, opt-in sorting, opt-in inline editing, and the\n * visual options that are forwarded to the underlying Table cell.\n */\nexport interface DataTableColumn<T> {\n /** Property of the row this column reads from. Doubles as the cell key. */\n key: keyof T;\n /** Column heading. */\n header: ReactNode;\n /** Custom cell renderer. Defaults to `String(row[key])`. */\n render?: (row: T) => ReactNode;\n /** Enable click-to-sort on this column's header. */\n sortable?: boolean;\n /** Text alignment forwarded to the Table cell. */\n align?: TableAlign;\n /** Responsive visibility priority forwarded to the Table cell. */\n priority?: TablePriority;\n /** Fixed column width forwarded to the Table cell. */\n width?: string | number;\n /**\n * Let cells in this column be edited in place. Requires `onCellChange` on the\n * table; without it the column stays read-only.\n */\n editable?: boolean;\n /** Editor input type. Default `\"text\"`. */\n editorType?: DataTableEditorType;\n /** Text the editor opens with. Defaults to `String(value ?? \"\")`. */\n formatEdit?: (row: T) => string;\n /**\n * Turn the typed string into the stored value. Defaults to the trimmed string,\n * or `Number(raw)` when `editorType` is `\"number\"`.\n */\n parse?: (raw: string, row: T) => unknown;\n /** Return a message to reject the edit, or `null` to accept it. */\n validate?: (value: unknown, row: T) => string | null;\n}\n\nexport interface DataTableProps<T> extends HTMLAttributes<HTMLDivElement> {\n /** Full, unfiltered dataset. Sorting/filtering/pagination happen client-side. */\n data: T[];\n /** Column definitions. */\n columns: DataTableColumn<T>[];\n /** Rows per page. Default 10. */\n pageSize?: number;\n /** Render a search input above the table. Default false. */\n searchable?: boolean;\n /**\n * Keys to match the search term against. When omitted, every column whose\n * value is a string or number is searched.\n */\n searchKeys?: (keyof T)[];\n /** Initial sort applied before any header interaction. */\n initialSort?: DataTableSort<T>;\n /** Stable key extractor for rows. Defaults to the row index. */\n rowKey?: (row: T, index: number) => string | number;\n /** Content shown when no rows match. */\n emptyMessage?: ReactNode;\n /**\n * Persist an accepted cell edit. Return a promise: while it is pending the cell\n * already shows the new value, and a rejection rolls that back and surfaces the\n * error in the cell. Without this prop no column is editable.\n */\n onCellChange?: (change: DataTableCellChange<T>) => void | Promise<void>;\n /** Override the PT-BR copy of the editing affordances. */\n editLabels?: Partial<DataTableEditLabels>;\n}\n\n/** Identity of one cell, stable across re-renders and pagination. */\nfunction cellId(rowKeyValue: string | number, columnKey: PropertyKey): string {\n return `${String(rowKeyValue)}::${String(columnKey)}`;\n}\n\nfunction headerText<T>(column: DataTableColumn<T>): string {\n return typeof column.header === \"string\" ? column.header : String(column.key);\n}\n\n/**\n * Stateful, headless data table built on top of {@link Table}. Adds\n * client-side searching, click-to-sort columns, pagination and opt-in inline\n * editing while delegating all table markup to the underlying Table component.\n *\n * - Clicking a sortable header cycles asc → desc → unsorted.\n * - Search matches a case-insensitive substring across `searchKeys`\n * (or every string/number column when not provided).\n * - Pagination is hidden when the result fits on a single page.\n * - A column with `editable` renders a button that opens an inline editor;\n * `Enter` commits, `Escape` discards, `Tab` walks to the next editable cell.\n *\n * Editing is strictly opt-in: with no `editable` column (or no `onCellChange`) the\n * rendered markup is byte-for-byte what it was before the feature existed, which\n * matters because the component is published.\n *\n * ## Optimistic, with a visible rollback\n *\n * An accepted edit is shown immediately and `onCellChange` runs in the background.\n * If it rejects, the cell returns to the old value **and** shows the reason as a\n * `role=\"alert\"` tied to the cell. A silent revert is worse than no optimistic\n * update at all: the user watched their edit appear and has no reason to doubt it.\n *\n * The header memo depends on `columns`, `sort` and the editing state only:\n * `toggleSort` and the commit callbacks are recreated each render but always close\n * over the same setters, so including them would rebuild every header on every\n * render without changing behaviour. That is why `exhaustive-deps` is silenced on\n * that dependency array.\n */\nexport function DataTable<T>({\n data,\n columns,\n pageSize = 10,\n searchable = false,\n searchKeys,\n initialSort,\n rowKey = (_row, index) => index,\n emptyMessage,\n onCellChange,\n editLabels,\n className,\n ...rest\n}: DataTableProps<T>) {\n const [search, setSearch] = useState<string>(\"\");\n const [sort, setSort] = useState<DataTableSort<T> | null>(initialSort ?? null);\n const { page, setPage } = usePagination(1, pageSize);\n const announce = useAnnounce();\n\n const [editing, setEditing] = useState<string | null>(null);\n const [refocus, setRefocus] = useState<string | null>(null);\n const [overrides, setOverrides] = useState<Record<string, unknown>>({});\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [saving, setSaving] = useState<Record<string, boolean>>({});\n\n const labels = useMemo<DataTableEditLabels>(\n () => ({ ...DEFAULT_EDIT_LABELS, ...editLabels }),\n [editLabels],\n );\n const editingEnabled = onCellChange !== undefined && columns.some((column) => column.editable);\n\n const effectiveSearchKeys = useMemo<(keyof T)[]>(() => {\n if (searchKeys && searchKeys.length > 0) return searchKeys;\n return columns\n .filter((column) => {\n const sample = data.find((row) => row[column.key] != null);\n const value = sample ? sample[column.key] : undefined;\n return typeof value === \"string\" || typeof value === \"number\";\n })\n .map((column) => column.key);\n }, [searchKeys, columns, data]);\n\n const filtered = useMemo<T[]>(() => {\n const term = search.trim().toLowerCase();\n if (!term || !searchable) return data;\n return data.filter((row) =>\n effectiveSearchKeys.some((key) => {\n const value = row[key];\n return value != null && String(value).toLowerCase().includes(term);\n }),\n );\n }, [data, search, searchable, effectiveSearchKeys]);\n\n const sorted = useMemo<T[]>(() => {\n if (!sort) return filtered;\n const factor = sort.direction === \"asc\" ? 1 : -1;\n return [...filtered].sort((a, b) => compareValues(a[sort.key], b[sort.key]) * factor);\n }, [filtered, sort]);\n\n const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));\n\n // Clamp the current page when the dataset shrinks (e.g. after filtering).\n useEffect(() => {\n if (page > totalPages) setPage(totalPages);\n }, [page, totalPages, setPage]);\n\n const safePage = Math.min(page, totalPages);\n const pageRows = useMemo<T[]>(() => {\n const start = (safePage - 1) * pageSize;\n return sorted.slice(start, start + pageSize);\n }, [sorted, safePage, pageSize]);\n\n function toggleSort(key: keyof T): void {\n setSort((current) => {\n if (!current || current.key !== key) return { key, direction: \"asc\" };\n if (current.direction === \"asc\") return { key, direction: \"desc\" };\n return null;\n });\n }\n\n const absoluteIndex = useCallback(\n (pageIndex: number) => (safePage - 1) * pageSize + pageIndex,\n [safePage, pageSize],\n );\n\n /**\n * Every editable cell on the page, row-major — the order `Tab` walks.\n *\n * Row-major and not column-major because a row is the record a user is\n * correcting; walking down a column would make them re-find their place on\n * every keystroke.\n */\n const editableCellIds = useMemo<string[]>(() => {\n if (!editingEnabled) return [];\n const ids: string[] = [];\n pageRows.forEach((row, index) => {\n const key = rowKey(row, absoluteIndex(index));\n for (const column of columns) {\n if (column.editable) ids.push(cellId(key, column.key));\n }\n });\n return ids;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editingEnabled, pageRows, columns, absoluteIndex]);\n\n const displayed = useCallback(\n (row: T, column: DataTableColumn<T>, id: string): unknown =>\n id in overrides ? overrides[id] : row[column.key],\n [overrides],\n );\n\n /**\n * Run the caller's `onCellChange` behind the optimistic update.\n *\n * Only the *success* is announced. The failure already renders as a\n * `role=\"alert\"` inside the cell, which screen readers read on insertion —\n * announcing it again from the shared region would read it twice and put the\n * same text in the document twice.\n */\n const persist = useCallback(\n async (id: string, column: DataTableColumn<T>, change: DataTableCellChange<T>) => {\n setSaving((current) => ({ ...current, [id]: true }));\n try {\n await onCellChange?.(change);\n announce(labels.saved(headerText(column)));\n } catch (error) {\n setOverrides((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n const message =\n error instanceof Error && error.message\n ? error.message\n : labels.saveFailed(headerText(column));\n setErrors((current) => ({ ...current, [id]: message }));\n } finally {\n setSaving((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n }\n },\n [onCellChange, announce, labels],\n );\n\n const moveFrom = useCallback(\n (id: string, move: CellCommitMove): void => {\n if (move === \"none\") {\n setEditing(null);\n setRefocus(id);\n return;\n }\n const index = editableCellIds.indexOf(id);\n const target = editableCellIds[index + (move === \"next\" ? 1 : -1)];\n if (target === undefined) {\n setEditing(null);\n setRefocus(id);\n return;\n }\n setEditing(target);\n setRefocus(null);\n },\n [editableCellIds],\n );\n\n /**\n * Parse, validate, stage optimistically, then save in the background.\n *\n * Validation runs before anything is staged, and a rejection leaves the editor\n * open with the message attached to the input — the user has to be able to fix\n * what they typed without retyping it.\n */\n const commit = useCallback(\n (\n row: T,\n column: DataTableColumn<T>,\n id: string,\n pageIndex: number,\n raw: string,\n move: CellCommitMove,\n ): void => {\n const previous = displayed(row, column, id);\n const currentText = column.formatEdit ? column.formatEdit(row) : String(previous ?? \"\");\n if (raw === currentText) {\n moveFrom(id, move);\n return;\n }\n\n const value = column.parse\n ? column.parse(raw, row)\n : column.editorType === \"number\"\n ? Number(raw)\n : raw.trim();\n\n const invalid = column.validate?.(value, row) ?? null;\n if (invalid) {\n setErrors((current) => ({ ...current, [id]: invalid }));\n return;\n }\n\n setErrors((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n setOverrides((current) => ({ ...current, [id]: value }));\n moveFrom(id, move);\n void persist(id, column, {\n row,\n key: column.key,\n value,\n previous,\n rowIndex: absoluteIndex(pageIndex),\n });\n },\n [displayed, moveFrom, persist, absoluteIndex],\n );\n\n const tableColumns = useMemo<TableColumn<T>[]>(\n () =>\n columns.map((column) => {\n const isSorted = sort?.key === column.key;\n const indicator = isSorted ? (sort?.direction === \"asc\" ? \" ▲\" : \" ▼\") : \"\";\n const header = column.sortable ? (\n <button\n type=\"button\"\n className={styles.sortButton}\n onClick={() => toggleSort(column.key)}\n aria-label={`Ordenar por ${headerText(column)}`}\n >\n {column.header}\n <span className={styles.sortIndicator} aria-hidden>\n {indicator}\n </span>\n </button>\n ) : (\n column.header\n );\n\n const plainCell = (row: T): ReactNode => {\n if (column.render) return column.render(row);\n return (row[column.key] as ReactNode) ?? null;\n };\n\n /**\n * Render an editable cell's content against the optimistic value.\n *\n * The row is shallow-patched rather than the value passed alongside it,\n * because a column with a custom `render` (a `<Money>`, a badge) reads\n * the row — handing it the stale row would show the old number under a\n * cell the user just changed.\n */\n const patchedCell = (row: T, value: unknown): ReactNode => {\n const patched = { ...row, [column.key]: value } as T;\n if (column.render) return column.render(patched);\n return (patched[column.key] as ReactNode) ?? null;\n };\n\n const editable = editingEnabled && column.editable === true;\n\n return {\n key: String(column.key),\n header,\n align: column.align,\n priority: column.priority,\n width: column.width,\n render: editable\n ? (row: T, index: number) => {\n const id = cellId(rowKey(row, absoluteIndex(index)), column.key);\n const value = displayed(row, column, id);\n const text = column.formatEdit\n ? column.formatEdit(row)\n : String(value ?? \"\");\n return (\n <EditableCell\n text={text}\n columnLabel={headerText(column)}\n rowNumber={index + 1}\n inputType={column.editorType ?? \"text\"}\n editing={editing === id}\n refocus={refocus === id}\n saving={saving[id] === true}\n error={errors[id] ?? null}\n errorId={`tempest-cell-error-${id.replace(/[^\\w-]/g, \"_\")}`}\n labels={labels}\n onOpen={() => {\n setEditing(id);\n setRefocus(null);\n }}\n onCommit={(raw, move) =>\n commit(row, column, id, index, raw, move)\n }\n onCancel={() => {\n setEditing(null);\n setRefocus(id);\n setErrors((current) => {\n const next = { ...current };\n delete next[id];\n return next;\n });\n }}\n >\n {patchedCell(row, value)}\n </EditableCell>\n );\n }\n : plainCell,\n };\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n columns,\n sort,\n editingEnabled,\n editing,\n refocus,\n saving,\n errors,\n labels,\n overrides,\n absoluteIndex,\n commit,\n ],\n );\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n {searchable && (\n <SearchBar\n value={search}\n onChange={(value) => {\n setSearch(value);\n setPage(1);\n }}\n wrapperClassName={styles.search}\n />\n )}\n <Table\n columns={tableColumns}\n data={pageRows}\n rowKey={(row, index) => rowKey(row, absoluteIndex(index))}\n emptyMessage={emptyMessage}\n />\n {totalPages > 1 && (\n <Pagination\n page={safePage}\n totalPages={totalPages}\n onPageChange={setPage}\n totalItems={sorted.length}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}